blob: 939b8faba0ff4c32ccee7b0cc7356fa6b55963bc [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 Thompson4a4854d2010-02-15 06:45:55 -080059/* dlfb keeps a list of urbs for efficient bulk transfers */
60static void dlfb_urb_completion(struct urb *urb);
61static struct urb *dlfb_get_urb(struct dlfb_data *dev);
62static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
63static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
64static void dlfb_free_urb_list(struct dlfb_data *dev);
65
Bernie Thompson3e8f3d62010-02-15 06:46:26 -080066/* other symbols with dependents */
67#ifdef CONFIG_FB_DEFERRED_IO
68static struct fb_deferred_io dlfb_defio;
69#endif
70
Bernie Thompson59277b62009-11-24 15:52:21 -080071/*
72 * Inserts a specific DisplayLink controller command into the provided
73 * buffer.
74 */
Bernie Thompson45742032010-02-15 06:46:04 -080075static char *dlfb_set_register(char *buf, u8 reg, u8 val)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070076{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080077 *buf++ = 0xAF;
78 *buf++ = 0x20;
79 *buf++ = reg;
80 *buf++ = val;
81 return buf;
Roberto De Ioris88e58b12009-06-03 14:03:06 -070082}
83
Bernie Thompson45742032010-02-15 06:46:04 -080084static char *dlfb_vidreg_lock(char *buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070085{
Bernie Thompson45742032010-02-15 06:46:04 -080086 return dlfb_set_register(buf, 0xFF, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -080087}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070088
Bernie Thompson45742032010-02-15 06:46:04 -080089static char *dlfb_vidreg_unlock(char *buf)
Bernie Thompson59277b62009-11-24 15:52:21 -080090{
Bernie Thompson45742032010-02-15 06:46:04 -080091 return dlfb_set_register(buf, 0xFF, 0xFF);
Bernie Thompson59277b62009-11-24 15:52:21 -080092}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070093
Bernie Thompson59277b62009-11-24 15:52:21 -080094/*
Bernie Thompson530f43a2010-02-15 06:46:21 -080095 * On/Off for driving the DisplayLink framebuffer to the display
Bernie Thompson59277b62009-11-24 15:52:21 -080096 */
Bernie Thompson530f43a2010-02-15 06:46:21 -080097static char *dlfb_enable_hvsync(char *buf, bool enable)
Bernie Thompson59277b62009-11-24 15:52:21 -080098{
Bernie Thompson530f43a2010-02-15 06:46:21 -080099 if (enable)
100 return dlfb_set_register(buf, 0x1F, 0x00);
101 else
102 return dlfb_set_register(buf, 0x1F, 0x01);
Bernie Thompson59277b62009-11-24 15:52:21 -0800103}
104
Bernie Thompson45742032010-02-15 06:46:04 -0800105static char *dlfb_set_color_depth(char *buf, u8 selection)
Bernie Thompson59277b62009-11-24 15:52:21 -0800106{
Bernie Thompson45742032010-02-15 06:46:04 -0800107 return dlfb_set_register(buf, 0x00, selection);
Bernie Thompson59277b62009-11-24 15:52:21 -0800108}
109
Bernie Thompson45742032010-02-15 06:46:04 -0800110static char *dlfb_set_base16bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800111{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800112 /* the base pointer is 16 bits wide, 0x20 is hi byte. */
Bernie Thompson45742032010-02-15 06:46:04 -0800113 wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
114 wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
115 return dlfb_set_register(wrptr, 0x22, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800116}
117
Bernie Thompson45742032010-02-15 06:46:04 -0800118static char *dlfb_set_base8bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800119{
Bernie Thompson45742032010-02-15 06:46:04 -0800120 wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
121 wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
122 return dlfb_set_register(wrptr, 0x28, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800123}
124
Bernie Thompson45742032010-02-15 06:46:04 -0800125static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800126{
Bernie Thompson45742032010-02-15 06:46:04 -0800127 wrptr = dlfb_set_register(wrptr, reg, value >> 8);
128 return dlfb_set_register(wrptr, reg+1, value);
Bernie Thompson59277b62009-11-24 15:52:21 -0800129}
130
131/*
132 * This is kind of weird because the controller takes some
133 * register values in a different byte order than other registers.
134 */
Bernie Thompson45742032010-02-15 06:46:04 -0800135static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800136{
Bernie Thompson45742032010-02-15 06:46:04 -0800137 wrptr = dlfb_set_register(wrptr, reg, value);
138 return dlfb_set_register(wrptr, reg+1, value >> 8);
Bernie Thompson59277b62009-11-24 15:52:21 -0800139}
140
141/*
142 * LFSR is linear feedback shift register. The reason we have this is
143 * because the display controller needs to minimize the clock depth of
144 * various counters used in the display path. So this code reverses the
145 * provided value into the lfsr16 value by counting backwards to get
146 * the value that needs to be set in the hardware comparator to get the
147 * same actual count. This makes sense once you read above a couple of
148 * times and think about it from a hardware perspective.
149 */
150static u16 lfsr16(u16 actual_count)
151{
152 u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
153
154 while (actual_count--) {
155 lv = ((lv << 1) |
156 (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
157 & 0xFFFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700158 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800159
160 return (u16) lv;
161}
162
163/*
164 * This does LFSR conversion on the value that is to be written.
165 * See LFSR explanation above for more detail.
166 */
Bernie Thompson45742032010-02-15 06:46:04 -0800167static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800168{
Bernie Thompson45742032010-02-15 06:46:04 -0800169 return dlfb_set_register_16(wrptr, reg, lfsr16(value));
Bernie Thompson59277b62009-11-24 15:52:21 -0800170}
171
172/*
173 * This takes a standard fbdev screeninfo struct and all of its monitor mode
174 * details and converts them into the DisplayLink equivalent register commands.
175 */
Bernie Thompson45742032010-02-15 06:46:04 -0800176static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
Bernie Thompson59277b62009-11-24 15:52:21 -0800177{
178 u16 xds, yds;
179 u16 xde, yde;
180 u16 yec;
181
Bernie Thompson59277b62009-11-24 15:52:21 -0800182 /* x display start */
183 xds = var->left_margin + var->hsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800184 wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800185 /* x display end */
186 xde = xds + var->xres;
Bernie Thompson45742032010-02-15 06:46:04 -0800187 wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800188
189 /* y display start */
190 yds = var->upper_margin + var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800191 wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800192 /* y display end */
193 yde = yds + var->yres;
Bernie Thompson45742032010-02-15 06:46:04 -0800194 wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800195
196 /* x end count is active + blanking - 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800197 wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
198 xde + var->right_margin - 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800199
200 /* libdlo hardcodes hsync start to 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800201 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800202
203 /* hsync end is width of sync pulse + 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800204 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800205
206 /* hpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800207 wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800208
209 /* yendcount is vertical active + vertical blanking */
210 yec = var->yres + var->upper_margin + var->lower_margin +
211 var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800212 wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
Bernie Thompson59277b62009-11-24 15:52:21 -0800213
214 /* libdlo hardcodes vsync start to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800215 wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800216
217 /* vsync end is width of vsync pulse */
Bernie Thompson45742032010-02-15 06:46:04 -0800218 wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800219
220 /* vpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800221 wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800222
223 /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
Bernie Thompson45742032010-02-15 06:46:04 -0800224 wrptr = dlfb_set_register_16be(wrptr, 0x1B,
225 200*1000*1000/var->pixclock);
Bernie Thompson59277b62009-11-24 15:52:21 -0800226
227 return wrptr;
228}
229
230/*
231 * This takes a standard fbdev screeninfo struct that was fetched or prepared
232 * and then generates the appropriate command sequence that then drives the
233 * display controller.
234 */
235static int dlfb_set_video_mode(struct dlfb_data *dev,
236 struct fb_var_screeninfo *var)
237{
238 char *buf;
239 char *wrptr;
240 int retval = 0;
241 int writesize;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800242 struct urb *urb;
Bernie Thompson59277b62009-11-24 15:52:21 -0800243
Bernie Thompson530f43a2010-02-15 06:46:21 -0800244 if (!atomic_read(&dev->usb_active))
245 return -EPERM;
246
247 urb = dlfb_get_urb(dev);
248 if (!urb)
249 return -ENOMEM;
250 buf = (char *) urb->transfer_buffer;
Bernie Thompson59277b62009-11-24 15:52:21 -0800251
252 /*
253 * This first section has to do with setting the base address on the
254 * controller * associated with the display. There are 2 base
255 * pointers, currently, we only * use the 16 bpp segment.
256 */
Bernie Thompson45742032010-02-15 06:46:04 -0800257 wrptr = dlfb_vidreg_lock(buf);
258 wrptr = dlfb_set_color_depth(wrptr, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -0800259 /* set base for 16bpp segment to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800260 wrptr = dlfb_set_base16bpp(wrptr, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800261 /* set base for 8bpp segment to end of fb */
Bernie Thompson45742032010-02-15 06:46:04 -0800262 wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800263
Bernie Thompson45742032010-02-15 06:46:04 -0800264 wrptr = dlfb_set_vid_cmds(wrptr, var);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800265 wrptr = dlfb_enable_hvsync(wrptr, true);
Bernie Thompson45742032010-02-15 06:46:04 -0800266 wrptr = dlfb_vidreg_unlock(wrptr);
Bernie Thompson59277b62009-11-24 15:52:21 -0800267
268 writesize = wrptr - buf;
269
Bernie Thompson530f43a2010-02-15 06:46:21 -0800270 retval = dlfb_submit_urb(dev, urb, writesize);
Bernie Thompson59277b62009-11-24 15:52:21 -0800271
Bernie Thompson59277b62009-11-24 15:52:21 -0800272 return retval;
273}
274
Bernie Thompson45742032010-02-15 06:46:04 -0800275static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700276{
277 unsigned long start = vma->vm_start;
278 unsigned long size = vma->vm_end - vma->vm_start;
279 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
280 unsigned long page, pos;
281
282 printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
283
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700284 if (offset + size > info->fix.smem_len)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700285 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700286
287 pos = (unsigned long)info->fix.smem_start + offset;
288
289 while (size > 0) {
290 page = vmalloc_to_pfn((void *)pos);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700291 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700292 return -EAGAIN;
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700293
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700294 start += PAGE_SIZE;
295 pos += PAGE_SIZE;
296 if (size > PAGE_SIZE)
297 size -= PAGE_SIZE;
298 else
299 size = 0;
300 }
301
302 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
303 return 0;
304
305}
306
Bernie Thompson530f43a2010-02-15 06:46:21 -0800307/*
308 * Trims identical data from front and back of line
309 * Sets new front buffer address and width
310 * And returns byte count of identical pixels
311 * Assumes CPU natural alignment (unsigned long)
312 * for back and front buffer ptrs and width
313 */
314static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700315{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800316 int j, k;
317 const unsigned long *back = (const unsigned long *) bback;
318 const unsigned long *front = (const unsigned long *) *bfront;
319 const int width = *width_bytes / sizeof(unsigned long);
320 int identical = width;
321 int start = width;
322 int end = width;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700323
Bernie Thompson530f43a2010-02-15 06:46:21 -0800324 prefetch((void *) front);
325 prefetch((void *) back);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700326
Bernie Thompson530f43a2010-02-15 06:46:21 -0800327 for (j = 0; j < width; j++) {
328 if (back[j] != front[j]) {
329 start = j;
330 break;
331 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700332 }
333
Bernie Thompson530f43a2010-02-15 06:46:21 -0800334 for (k = width - 1; k > j; k--) {
335 if (back[k] != front[k]) {
336 end = k+1;
337 break;
338 }
339 }
340
341 identical = start + (width - end);
342 *bfront = (u8 *) &front[start];
343 *width_bytes = (end - start) * sizeof(unsigned long);
344
345 return identical * sizeof(unsigned long);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700346}
347
348/*
Bernie Thompson530f43a2010-02-15 06:46:21 -0800349Render a command stream for an encoded horizontal line segment of pixels.
350
351A command buffer holds several commands.
352It always begins with a fresh command header
353(the protocol doesn't require this, but we enforce it to allow
354multiple buffers to be potentially encoded and sent in parallel).
355A single command encodes one contiguous horizontal line of pixels
356
357The function relies on the client to do all allocation, so that
358rendering can be done directly to output buffers (e.g. USB URBs).
359The function fills the supplied command buffer, providing information
360on where it left off, so the client may call in again with additional
361buffers if the line will take several buffers to complete.
362
363A single command can transmit a maximum of 256 pixels,
364regardless of the compression ratio (protocol design limit).
365To the hardware, 0 for a size byte means 256
366
367Rather than 256 pixel commands which are either rl or raw encoded,
368the rlx command simply assumes alternating raw and rl spans within one cmd.
369This has a slightly larger header overhead, but produces more even results.
370It also processes all data (read and write) in a single pass.
371Performance benchmarks of common cases show it having just slightly better
372compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
373But for very rl friendly data, will compress not quite as well.
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700374*/
Bernie Thompson530f43a2010-02-15 06:46:21 -0800375static void dlfb_compress_hline(
376 const uint16_t **pixel_start_ptr,
377 const uint16_t *const pixel_end,
378 uint32_t *device_address_ptr,
379 uint8_t **command_buffer_ptr,
380 const uint8_t *const cmd_buffer_end)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700381{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800382 const uint16_t *pixel = *pixel_start_ptr;
383 uint32_t dev_addr = *device_address_ptr;
384 uint8_t *cmd = *command_buffer_ptr;
385 const int bpp = 2;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700386
Bernie Thompson530f43a2010-02-15 06:46:21 -0800387 while ((pixel_end > pixel) &&
388 (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
389 uint8_t *raw_pixels_count_byte = 0;
390 uint8_t *cmd_pixels_count_byte = 0;
391 const uint16_t *raw_pixel_start = 0;
392 const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
393 const uint32_t be_dev_addr = cpu_to_be32(dev_addr);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700394
Bernie Thompson530f43a2010-02-15 06:46:21 -0800395 prefetchw((void *) cmd); /* pull in one cache line at least */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700396
Bernie Thompson530f43a2010-02-15 06:46:21 -0800397 *cmd++ = 0xAF;
398 *cmd++ = 0x6B;
399 *cmd++ = (uint8_t) ((be_dev_addr >> 8) & 0xFF);
400 *cmd++ = (uint8_t) ((be_dev_addr >> 16) & 0xFF);
401 *cmd++ = (uint8_t) ((be_dev_addr >> 24) & 0xFF);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700402
Bernie Thompson530f43a2010-02-15 06:46:21 -0800403 cmd_pixels_count_byte = cmd++; /* we'll know this later */
404 cmd_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700405
Bernie Thompson530f43a2010-02-15 06:46:21 -0800406 raw_pixels_count_byte = cmd++; /* we'll know this later */
407 raw_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700408
Bernie Thompson530f43a2010-02-15 06:46:21 -0800409 cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
410 min((int)(pixel_end - pixel),
411 (int)(cmd_buffer_end - cmd) / bpp));
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700412
Bernie Thompson530f43a2010-02-15 06:46:21 -0800413 prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700414
Bernie Thompson530f43a2010-02-15 06:46:21 -0800415 while (pixel < cmd_pixel_end) {
416 const uint16_t * const repeating_pixel = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700417
Bernie Thompson530f43a2010-02-15 06:46:21 -0800418 *(uint16_t *)cmd = cpu_to_be16p(pixel);
419 cmd += 2;
420 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700421
Bernie Thompson530f43a2010-02-15 06:46:21 -0800422 if (unlikely((pixel < cmd_pixel_end) &&
423 (*pixel == *repeating_pixel))) {
424 /* go back and fill in raw pixel count */
425 *raw_pixels_count_byte = ((repeating_pixel -
426 raw_pixel_start) + 1) & 0xFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700427
Bernie Thompson530f43a2010-02-15 06:46:21 -0800428 while ((pixel < cmd_pixel_end)
429 && (*pixel == *repeating_pixel)) {
430 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700431 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800432
Bernie Thompson530f43a2010-02-15 06:46:21 -0800433 /* immediately after raw data is repeat byte */
434 *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
Bernie Thompson59277b62009-11-24 15:52:21 -0800435
Bernie Thompson530f43a2010-02-15 06:46:21 -0800436 /* Then start another raw pixel span */
437 raw_pixel_start = pixel;
438 raw_pixels_count_byte = cmd++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700439 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700440 }
441
Bernie Thompson530f43a2010-02-15 06:46:21 -0800442 if (pixel > raw_pixel_start) {
443 /* finalize last RAW span */
444 *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
445 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700446
Bernie Thompson530f43a2010-02-15 06:46:21 -0800447 *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
448 dev_addr += (pixel - cmd_pixel_start) * bpp;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700449 }
450
Bernie Thompson530f43a2010-02-15 06:46:21 -0800451 if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
452 /* Fill leftover bytes with no-ops */
453 if (cmd_buffer_end > cmd)
454 memset(cmd, 0xAF, cmd_buffer_end - cmd);
455 cmd = (uint8_t *) cmd_buffer_end;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700456 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700457
Bernie Thompson530f43a2010-02-15 06:46:21 -0800458 *command_buffer_ptr = cmd;
459 *pixel_start_ptr = pixel;
460 *device_address_ptr = dev_addr;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700461
Bernie Thompson530f43a2010-02-15 06:46:21 -0800462 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700463}
464
Bernie Thompson530f43a2010-02-15 06:46:21 -0800465/*
466 * There are 3 copies of every pixel: The front buffer that the fbdev
467 * client renders to, the actual framebuffer across the USB bus in hardware
468 * (that we can only write to, slowly, and can never read), and (optionally)
469 * our shadow copy that tracks what's been sent to that hardware buffer.
470 */
471static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
472 const char *front, char **urb_buf_ptr,
473 u32 byte_offset, u32 byte_width,
474 int *ident_ptr, int *sent_ptr)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700475{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800476 const u8 *line_start, *line_end, *next_pixel;
477 u32 dev_addr = dev->base16 + byte_offset;
478 struct urb *urb = *urb_ptr;
479 u8 *cmd = *urb_buf_ptr;
480 u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700481
Bernie Thompson530f43a2010-02-15 06:46:21 -0800482 line_start = (u8 *) (front + byte_offset);
483 next_pixel = line_start;
484 line_end = next_pixel + byte_width;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700485
Bernie Thompson530f43a2010-02-15 06:46:21 -0800486 if (dev->backing_buffer) {
487 int offset;
488 const u8 *back_start = (u8 *) (dev->backing_buffer
489 + byte_offset);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700490
Bernie Thompson530f43a2010-02-15 06:46:21 -0800491 *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
492 &byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700493
Bernie Thompson530f43a2010-02-15 06:46:21 -0800494 offset = next_pixel - line_start;
495 line_end = next_pixel + byte_width;
496 dev_addr += offset;
497 back_start += offset;
498 line_start += offset;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700499
Bernie Thompson530f43a2010-02-15 06:46:21 -0800500 memcpy((char *)back_start, (char *) line_start,
501 byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700502 }
503
Bernie Thompson530f43a2010-02-15 06:46:21 -0800504 while (next_pixel < line_end) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700505
Bernie Thompson530f43a2010-02-15 06:46:21 -0800506 dlfb_compress_hline((const uint16_t **) &next_pixel,
507 (const uint16_t *) line_end, &dev_addr,
508 (u8 **) &cmd, (u8 *) cmd_end);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700509
Bernie Thompson530f43a2010-02-15 06:46:21 -0800510 if (cmd >= cmd_end) {
511 int len = cmd - (u8 *) urb->transfer_buffer;
512 if (dlfb_submit_urb(dev, urb, len))
513 return; /* lost pixels is set */
514 *sent_ptr += len;
515 urb = dlfb_get_urb(dev);
516 if (!urb)
517 return; /* lost_pixels is set */
518 *urb_ptr = urb;
519 cmd = urb->transfer_buffer;
520 cmd_end = &cmd[urb->transfer_buffer_length];
521 }
522 }
523
524 *urb_buf_ptr = cmd;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700525}
526
Bernie Thompson530f43a2010-02-15 06:46:21 -0800527int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
528 int width, int height, char *data)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700529{
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700530 int i, ret;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800531 char *cmd;
532 cycles_t start_cycles, end_cycles;
533 int bytes_sent = 0;
534 int bytes_identical = 0;
535 struct urb *urb;
536 int aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700537
Bernie Thompson530f43a2010-02-15 06:46:21 -0800538 start_cycles = get_cycles();
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700539
Bernie Thompson530f43a2010-02-15 06:46:21 -0800540 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
541 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
542 x = aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700543
Bernie Thompson530f43a2010-02-15 06:46:21 -0800544 if ((width <= 0) ||
545 (x + width > dev->info->var.xres) ||
546 (y + height > dev->info->var.yres))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700547 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700548
Bernie Thompson530f43a2010-02-15 06:46:21 -0800549 if (!atomic_read(&dev->usb_active))
550 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700551
Bernie Thompson530f43a2010-02-15 06:46:21 -0800552 urb = dlfb_get_urb(dev);
553 if (!urb)
554 return 0;
555 cmd = urb->transfer_buffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700556
Bernie Thompson530f43a2010-02-15 06:46:21 -0800557 for (i = y; i < y + height ; i++) {
558 const int line_offset = dev->info->fix.line_length * i;
559 const int byte_offset = line_offset + (x * BPP);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700560
Bernie Thompson530f43a2010-02-15 06:46:21 -0800561 dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
562 &cmd, byte_offset, width * BPP,
563 &bytes_identical, &bytes_sent);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700564 }
565
Bernie Thompson530f43a2010-02-15 06:46:21 -0800566 if (cmd > (char *) urb->transfer_buffer) {
567 /* Send partial buffer remaining before exiting */
568 int len = cmd - (char *) urb->transfer_buffer;
569 ret = dlfb_submit_urb(dev, urb, len);
570 bytes_sent += len;
571 } else
572 dlfb_urb_completion(urb);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700573
Bernie Thompson530f43a2010-02-15 06:46:21 -0800574 atomic_add(bytes_sent, &dev->bytes_sent);
575 atomic_add(bytes_identical, &dev->bytes_identical);
576 atomic_add(width*height*2, &dev->bytes_rendered);
577 end_cycles = get_cycles();
578 atomic_add(((unsigned int) ((end_cycles - start_cycles)
579 >> 10)), /* Kcycles */
580 &dev->cpu_kcycles_used);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700581
Bernie Thompson530f43a2010-02-15 06:46:21 -0800582 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700583}
584
Bernie Thompson530f43a2010-02-15 06:46:21 -0800585/* hardware has native COPY command (see libdlo), but not worth it for fbcon */
Bernie Thompson45742032010-02-15 06:46:04 -0800586static void dlfb_ops_copyarea(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800587 const struct fb_copyarea *area)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700588{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800589
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700590 struct dlfb_data *dev = info->par;
591
Bernie Thompson530f43a2010-02-15 06:46:21 -0800592#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
593
594 sys_copyarea(info, area);
595
596 dlfb_handle_damage(dev, area->dx, area->dy,
597 area->width, area->height, info->screen_base);
598#endif
599 atomic_inc(&dev->copy_count);
600
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700601}
602
Bernie Thompson45742032010-02-15 06:46:04 -0800603static void dlfb_ops_imageblit(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800604 const struct fb_image *image)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700605{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700606 struct dlfb_data *dev = info->par;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800607
608#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
609
610 sys_imageblit(info, image);
611
612 dlfb_handle_damage(dev, image->dx, image->dy,
613 image->width, image->height, info->screen_base);
614
615#endif
616
617 atomic_inc(&dev->blit_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700618}
619
Bernie Thompson45742032010-02-15 06:46:04 -0800620static void dlfb_ops_fillrect(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800621 const struct fb_fillrect *rect)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700622{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700623 struct dlfb_data *dev = info->par;
624
Bernie Thompson530f43a2010-02-15 06:46:21 -0800625#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
626
627 sys_fillrect(info, rect);
628
629 dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
630 rect->height, info->screen_base);
631#endif
632
633 atomic_inc(&dev->fill_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700634
635}
636
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800637static void dlfb_get_edid(struct dlfb_data *dev)
638{
639 int i;
640 int ret;
641 char rbuf[2];
642
643 for (i = 0; i < sizeof(dev->edid); i++) {
644 ret = usb_control_msg(dev->udev,
645 usb_rcvctrlpipe(dev->udev, 0), (0x02),
646 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
647 0);
648 dev->edid[i] = rbuf[1];
649 }
650}
651
Bernie Thompson45742032010-02-15 06:46:04 -0800652static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800653 unsigned long arg)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700654{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800655
656 struct dlfb_data *dev = info->par;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700657 struct dloarea *area = NULL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700658
Bernie Thompson530f43a2010-02-15 06:46:21 -0800659 if (!atomic_read(&dev->usb_active))
660 return 0;
661
662 /* TODO: Update X server to get this from sysfs instead */
663 if (cmd == DLFB_IOCTL_RETURN_EDID) {
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700664 char *edid = (char *)arg;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800665 dlfb_get_edid(dev);
666 if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700667 return -EFAULT;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700668 return 0;
669 }
670
Bernie Thompson530f43a2010-02-15 06:46:21 -0800671 /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
672 if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700673
674 area = (struct dloarea *)arg;
675
676 if (area->x < 0)
677 area->x = 0;
678
679 if (area->x > info->var.xres)
680 area->x = info->var.xres;
681
682 if (area->y < 0)
683 area->y = 0;
684
685 if (area->y > info->var.yres)
686 area->y = info->var.yres;
687
Bernie Thompson530f43a2010-02-15 06:46:21 -0800688 atomic_set(&dev->use_defio, 0);
689
690 dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700691 info->screen_base);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800692 atomic_inc(&dev->damage_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700693 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700694
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700695 return 0;
696}
697
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700698/* taken from vesafb */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700699static int
Bernie Thompson45742032010-02-15 06:46:04 -0800700dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700701 unsigned blue, unsigned transp, struct fb_info *info)
702{
703 int err = 0;
704
705 if (regno >= info->cmap.len)
706 return 1;
707
708 if (regno < 16) {
709 if (info->var.red.offset == 10) {
710 /* 1:5:5:5 */
711 ((u32 *) (info->pseudo_palette))[regno] =
712 ((red & 0xf800) >> 1) |
713 ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
714 } else {
715 /* 0:5:6:5 */
716 ((u32 *) (info->pseudo_palette))[regno] =
717 ((red & 0xf800)) |
718 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
719 }
720 }
721
722 return err;
723}
724
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800725/*
726 * It's common for several clients to have framebuffer open simultaneously.
727 * e.g. both fbcon and X. Makes things interesting.
728 */
729static int dlfb_ops_open(struct fb_info *info, int user)
730{
731 struct dlfb_data *dev = info->par;
732
733/* if (user == 0)
734 * We could special case kernel mode clients (fbcon) here
735 */
736
737 mutex_lock(&dev->fb_open_lock);
738
739 dev->fb_count++;
740
741#ifdef CONFIG_FB_DEFERRED_IO
742 if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
743 /* enable defio */
744 info->fbdefio = &dlfb_defio;
745 fb_deferred_io_init(info);
746 }
747#endif
748
749 dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
750 info->node, user, info, dev->fb_count);
751
752 mutex_unlock(&dev->fb_open_lock);
753
754 return 0;
755}
756
Bernie Thompson45742032010-02-15 06:46:04 -0800757static int dlfb_ops_release(struct fb_info *info, int user)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700758{
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800759 struct dlfb_data *dev = info->par;
760
761 mutex_lock(&dev->fb_open_lock);
762
763 dev->fb_count--;
764
765#ifdef CONFIG_FB_DEFERRED_IO
766 if ((dev->fb_count == 0) && (info->fbdefio)) {
767 fb_deferred_io_cleanup(info);
768 info->fbdefio = NULL;
769 info->fbops->fb_mmap = dlfb_ops_mmap;
770 }
771#endif
772
773 dl_notice("release /dev/fb%d user=%d count=%d\n",
774 info->node, user, dev->fb_count);
775
776 mutex_unlock(&dev->fb_open_lock);
777
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700778 return 0;
779}
780
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800781/*
782 * Called when all client interfaces to start transactions have been disabled,
783 * and all references to our device instance (dlfb_data) are released.
784 * Every transaction must have a reference, so we know are fully spun down
785 */
786static void dlfb_delete(struct kref *kref)
787{
788 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
789
790 if (dev->backing_buffer)
791 vfree(dev->backing_buffer);
792
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800793 mutex_destroy(&dev->fb_open_lock);
794
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800795 kfree(dev);
796}
797
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800798/*
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800799 * Called by fbdev as last part of unregister_framebuffer() process
800 * No new clients can open connections. Deallocate everything fb_info.
801 */
802static void dlfb_ops_destroy(struct fb_info *info)
803{
804 struct dlfb_data *dev = info->par;
805
806 if (info->cmap.len != 0)
807 fb_dealloc_cmap(&info->cmap);
808 if (info->monspecs.modedb)
809 fb_destroy_modedb(info->monspecs.modedb);
810 if (info->screen_base)
811 vfree(info->screen_base);
812
813 fb_destroy_modelist(&info->modelist);
814
815 framebuffer_release(info);
816
817 /* ref taken before register_framebuffer() for dlfb_data clients */
818 kref_put(&dev->kref, dlfb_delete);
819}
820
821/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800822 * Check whether a video mode is supported by the DisplayLink chip
823 * We start from monitor's modes, so don't need to filter that here
824 */
825static int dlfb_is_valid_mode(struct fb_videomode *mode,
826 struct fb_info *info)
827{
828 struct dlfb_data *dev = info->par;
829
830 if (mode->xres * mode->yres > dev->sku_pixel_limit)
831 return 0;
832
833 return 1;
834}
835
836static void dlfb_var_color_format(struct fb_var_screeninfo *var)
837{
838 const struct fb_bitfield red = { 11, 5, 0 };
839 const struct fb_bitfield green = { 5, 6, 0 };
840 const struct fb_bitfield blue = { 0, 5, 0 };
841
842 var->bits_per_pixel = 16;
843 var->red = red;
844 var->green = green;
845 var->blue = blue;
846}
847
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800848static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
849 struct fb_info *info)
850{
851 struct fb_videomode mode;
852
853 /* TODO: support dynamically changing framebuffer size */
854 if ((var->xres * var->yres * 2) > info->fix.smem_len)
855 return -EINVAL;
856
857 /* set device-specific elements of var unrelated to mode */
858 dlfb_var_color_format(var);
859
860 fb_var_to_videomode(&mode, var);
861
862 if (!dlfb_is_valid_mode(&mode, info))
863 return -EINVAL;
864
865 return 0;
866}
867
868static int dlfb_ops_set_par(struct fb_info *info)
869{
870 struct dlfb_data *dev = info->par;
871
872 dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
873
874 return dlfb_set_video_mode(dev, &info->var);
875}
876
Bernie Thompson45742032010-02-15 06:46:04 -0800877static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700878{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800879 struct dlfb_data *dev = info->par;
880 char *bufptr;
881 struct urb *urb;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700882
Bernie Thompson530f43a2010-02-15 06:46:21 -0800883 urb = dlfb_get_urb(dev);
884 if (!urb)
885 return 0;
886 bufptr = (char *) urb->transfer_buffer;
887
888 /* overloading usb_active. UNBLANK can conflict with teardown */
889
890 bufptr = dlfb_vidreg_lock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700891 if (blank_mode != FB_BLANK_UNBLANK) {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800892 atomic_set(&dev->usb_active, 0);
893 bufptr = dlfb_enable_hvsync(bufptr, false);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700894 } else {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800895 atomic_set(&dev->usb_active, 1);
896 bufptr = dlfb_enable_hvsync(bufptr, true);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700897 }
Bernie Thompson530f43a2010-02-15 06:46:21 -0800898 bufptr = dlfb_vidreg_unlock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700899
Bernie Thompson530f43a2010-02-15 06:46:21 -0800900 dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700901
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700902 return 0;
903}
904
905static struct fb_ops dlfb_ops = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800906 .owner = THIS_MODULE,
Bernie Thompson45742032010-02-15 06:46:04 -0800907 .fb_setcolreg = dlfb_ops_setcolreg,
908 .fb_fillrect = dlfb_ops_fillrect,
909 .fb_copyarea = dlfb_ops_copyarea,
910 .fb_imageblit = dlfb_ops_imageblit,
911 .fb_mmap = dlfb_ops_mmap,
912 .fb_ioctl = dlfb_ops_ioctl,
Bernie Thompson3e8f3d62010-02-15 06:46:26 -0800913 .fb_open = dlfb_ops_open,
Bernie Thompson45742032010-02-15 06:46:04 -0800914 .fb_release = dlfb_ops_release,
915 .fb_blank = dlfb_ops_blank,
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800916 .fb_check_var = dlfb_ops_check_var,
917 .fb_set_par = dlfb_ops_set_par,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700918};
919
Bernie Thompsoncc403dc2010-02-15 06:45:49 -0800920/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800921 * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
922 * Then parses EDID into three places used by various parts of fbdev:
923 * fb_var_screeninfo contains the timing of the monitor's preferred mode
924 * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
925 * fb_info.modelist is a linked list of all monitor & VESA modes which work
926 *
927 * If EDID is not readable/valid, then modelist is all VESA modes,
928 * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
929 * Returns 0 if EDID parses successfully
930 */
931static int dlfb_parse_edid(struct dlfb_data *dev,
932 struct fb_var_screeninfo *var,
933 struct fb_info *info)
934{
935 int i;
936 const struct fb_videomode *default_vmode = NULL;
937 int result = 0;
938
939 fb_destroy_modelist(&info->modelist);
940 memset(&info->monspecs, 0, sizeof(info->monspecs));
941
942 dlfb_get_edid(dev);
943 fb_edid_to_monspecs(dev->edid, &info->monspecs);
944
945 if (info->monspecs.modedb_len > 0) {
946
947 for (i = 0; i < info->monspecs.modedb_len; i++) {
948 if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
949 fb_add_videomode(&info->monspecs.modedb[i],
950 &info->modelist);
951 }
952
953 default_vmode = fb_find_best_display(&info->monspecs,
954 &info->modelist);
955 } else {
956 struct fb_videomode fb_vmode = {0};
957
958 dl_err("Unable to get valid EDID from device/display\n");
959 result = 1;
960
961 /*
962 * Add the standard VESA modes to our modelist
963 * Since we don't have EDID, there may be modes that
964 * overspec monitor and/or are incorrect aspect ratio, etc.
965 * But at least the user has a chance to choose
966 */
967 for (i = 0; i < VESA_MODEDB_SIZE; i++) {
968 if (dlfb_is_valid_mode((struct fb_videomode *)
969 &vesa_modes[i], info))
970 fb_add_videomode(&vesa_modes[i],
971 &info->modelist);
972 }
973
974 /*
975 * default to resolution safe for projectors
976 * (since they are most common case without EDID)
977 */
978 fb_vmode.xres = 800;
979 fb_vmode.yres = 600;
980 fb_vmode.refresh = 60;
981 default_vmode = fb_find_nearest_mode(&fb_vmode,
982 &info->modelist);
983 }
984
985 fb_videomode_to_var(var, default_vmode);
986 dlfb_var_color_format(var);
987
988 return result;
989}
990
991static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
992 struct device_attribute *a, char *buf) {
993 struct fb_info *fb_info = dev_get_drvdata(fbdev);
994 struct dlfb_data *dev = fb_info->par;
995 return snprintf(buf, PAGE_SIZE, "%u\n",
996 atomic_read(&dev->bytes_rendered));
997}
998
999static ssize_t metrics_bytes_identical_show(struct device *fbdev,
1000 struct device_attribute *a, char *buf) {
1001 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1002 struct dlfb_data *dev = fb_info->par;
1003 return snprintf(buf, PAGE_SIZE, "%u\n",
1004 atomic_read(&dev->bytes_identical));
1005}
1006
1007static ssize_t metrics_bytes_sent_show(struct device *fbdev,
1008 struct device_attribute *a, char *buf) {
1009 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1010 struct dlfb_data *dev = fb_info->par;
1011 return snprintf(buf, PAGE_SIZE, "%u\n",
1012 atomic_read(&dev->bytes_sent));
1013}
1014
1015static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
1016 struct device_attribute *a, char *buf) {
1017 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1018 struct dlfb_data *dev = fb_info->par;
1019 return snprintf(buf, PAGE_SIZE, "%u\n",
1020 atomic_read(&dev->cpu_kcycles_used));
1021}
1022
1023static ssize_t metrics_misc_show(struct device *fbdev,
1024 struct device_attribute *a, char *buf) {
1025 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1026 struct dlfb_data *dev = fb_info->par;
1027 return snprintf(buf, PAGE_SIZE,
1028 "Calls to\ndamage: %u\nblit: %u\n"
1029 "defio faults: %u\ncopy: %u\n"
1030 "fill: %u\n\n"
1031 "active framebuffer clients: %d\n"
1032 "urbs available %d(%d)\n"
1033 "Shadow framebuffer in use? %s\n"
1034 "Any lost pixels? %s\n",
1035 atomic_read(&dev->damage_count),
1036 atomic_read(&dev->blit_count),
1037 atomic_read(&dev->defio_fault_count),
1038 atomic_read(&dev->copy_count),
1039 atomic_read(&dev->fill_count),
1040 dev->fb_count,
1041 dev->urbs.available, dev->urbs.limit_sem.count,
1042 (dev->backing_buffer) ? "yes" : "no",
1043 atomic_read(&dev->lost_pixels) ? "yes" : "no");
1044}
1045
1046static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
1047 char *buf, loff_t off, size_t count) {
1048 struct device *fbdev = container_of(kobj, struct device, kobj);
1049 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1050 struct dlfb_data *dev = fb_info->par;
1051 char *edid = &dev->edid[0];
1052 const size_t size = sizeof(dev->edid);
1053
1054 if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
1055 return 0;
1056
1057 if (off >= size)
1058 return 0;
1059
1060 if (off + count > size)
1061 count = size - off;
1062 memcpy(buf, edid + off, count);
1063
1064 return count;
1065}
1066
1067
1068static ssize_t metrics_reset_store(struct device *fbdev,
1069 struct device_attribute *attr,
1070 const char *buf, size_t count)
1071{
1072 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1073 struct dlfb_data *dev = fb_info->par;
1074
1075 atomic_set(&dev->bytes_rendered, 0);
1076 atomic_set(&dev->bytes_identical, 0);
1077 atomic_set(&dev->bytes_sent, 0);
1078 atomic_set(&dev->cpu_kcycles_used, 0);
1079 atomic_set(&dev->blit_count, 0);
1080 atomic_set(&dev->copy_count, 0);
1081 atomic_set(&dev->fill_count, 0);
1082 atomic_set(&dev->defio_fault_count, 0);
1083 atomic_set(&dev->damage_count, 0);
1084
1085 return count;
1086}
1087
1088static ssize_t use_defio_show(struct device *fbdev,
1089 struct device_attribute *a, char *buf) {
1090 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1091 struct dlfb_data *dev = fb_info->par;
1092 return snprintf(buf, PAGE_SIZE, "%d\n",
1093 atomic_read(&dev->use_defio));
1094}
1095
1096static ssize_t use_defio_store(struct device *fbdev,
1097 struct device_attribute *attr,
1098 const char *buf, size_t count)
1099{
1100 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1101 struct dlfb_data *dev = fb_info->par;
1102
1103 if (count > 0) {
1104 if (buf[0] == '0')
1105 atomic_set(&dev->use_defio, 0);
1106 if (buf[0] == '1')
1107 atomic_set(&dev->use_defio, 1);
1108 }
1109 return count;
1110}
1111
1112static struct bin_attribute edid_attr = {
1113 .attr.name = "edid",
1114 .attr.mode = 0444,
1115 .size = 128,
1116 .read = edid_show,
1117};
1118
1119static struct device_attribute fb_device_attrs[] = {
1120 __ATTR_RO(metrics_bytes_rendered),
1121 __ATTR_RO(metrics_bytes_identical),
1122 __ATTR_RO(metrics_bytes_sent),
1123 __ATTR_RO(metrics_cpu_kcycles_used),
1124 __ATTR_RO(metrics_misc),
1125 __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
1126 __ATTR_RW(use_defio),
1127};
1128
Bernie Thompson3e8f3d62010-02-15 06:46:26 -08001129#ifdef CONFIG_FB_DEFERRED_IO
1130static void dlfb_dpy_deferred_io(struct fb_info *info,
1131 struct list_head *pagelist)
1132{
1133 struct page *cur;
1134 struct fb_deferred_io *fbdefio = info->fbdefio;
1135 struct dlfb_data *dev = info->par;
1136 struct urb *urb;
1137 char *cmd;
1138 cycles_t start_cycles, end_cycles;
1139 int bytes_sent = 0;
1140 int bytes_identical = 0;
1141 int bytes_rendered = 0;
1142 int fault_count = 0;
1143
1144 if (!atomic_read(&dev->use_defio))
1145 return;
1146
1147 if (!atomic_read(&dev->usb_active))
1148 return;
1149
1150 start_cycles = get_cycles();
1151
1152 urb = dlfb_get_urb(dev);
1153 if (!urb)
1154 return;
1155 cmd = urb->transfer_buffer;
1156
1157 /* walk the written page list and render each to device */
1158 list_for_each_entry(cur, &fbdefio->pagelist, lru) {
1159 dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
1160 &cmd, cur->index << PAGE_SHIFT,
1161 PAGE_SIZE, &bytes_identical, &bytes_sent);
1162 bytes_rendered += PAGE_SIZE;
1163 fault_count++;
1164 }
1165
1166 if (cmd > (char *) urb->transfer_buffer) {
1167 /* Send partial buffer remaining before exiting */
1168 int len = cmd - (char *) urb->transfer_buffer;
1169 dlfb_submit_urb(dev, urb, len);
1170 bytes_sent += len;
1171 } else
1172 dlfb_urb_completion(urb);
1173
1174 atomic_add(fault_count, &dev->defio_fault_count);
1175 atomic_add(bytes_sent, &dev->bytes_sent);
1176 atomic_add(bytes_identical, &dev->bytes_identical);
1177 atomic_add(bytes_rendered, &dev->bytes_rendered);
1178 end_cycles = get_cycles();
1179 atomic_add(((unsigned int) ((end_cycles - start_cycles)
1180 >> 10)), /* Kcycles */
1181 &dev->cpu_kcycles_used);
1182}
1183
1184static struct fb_deferred_io dlfb_defio = {
1185 .delay = 5,
1186 .deferred_io = dlfb_dpy_deferred_io,
1187};
1188
1189#endif
1190
Bernie Thompson7d9485e2010-02-15 06:46:08 -08001191/*
Bernie Thompsoncc403dc2010-02-15 06:45:49 -08001192 * This is necessary before we can communicate with the display controller.
1193 */
1194static int dlfb_select_std_channel(struct dlfb_data *dev)
1195{
1196 int ret;
1197 u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7,
1198 0x1C, 0x88, 0x5E, 0x15,
1199 0x60, 0xFE, 0xC6, 0x97,
1200 0x16, 0x3D, 0x47, 0xF2 };
1201
1202 ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
1203 NR_USB_REQUEST_CHANNEL,
1204 (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
1205 set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
1206 return ret;
1207}
1208
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001209
1210static int dlfb_usb_probe(struct usb_interface *interface,
Bernie Thompson59277b62009-11-24 15:52:21 -08001211 const struct usb_device_id *id)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001212{
Bernie Thompson59277b62009-11-24 15:52:21 -08001213 struct usb_device *usbdev;
1214 struct dlfb_data *dev;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001215 struct fb_info *info;
Bernie Thompson59277b62009-11-24 15:52:21 -08001216 int videomemorysize;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001217 int i;
Bernie Thompson59277b62009-11-24 15:52:21 -08001218 unsigned char *videomemory;
1219 int retval = -ENOMEM;
1220 struct fb_var_screeninfo *var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001221 int registered = 0;
1222 u16 *pix_framebuffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001223
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001224 /* usb initialization */
1225
1226 usbdev = interface_to_usbdev(interface);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001227
Bernie Thompson59277b62009-11-24 15:52:21 -08001228 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1229 if (dev == NULL) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001230 err("dlfb_usb_probe: failed alloc of dev struct\n");
1231 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001232 }
1233
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001234 /* we need to wait for both usb and fbdev to spin down on disconnect */
1235 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
1236 kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
1237
Bernie Thompson59277b62009-11-24 15:52:21 -08001238 dev->udev = usbdev;
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001239 dev->gdev = &usbdev->dev; /* our generic struct device * */
Bernie Thompson59277b62009-11-24 15:52:21 -08001240 usb_set_intfdata(interface, dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001241
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001242 if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
1243 retval = -ENOMEM;
1244 dl_err("dlfb_alloc_urb_list failed\n");
1245 goto error;
1246 }
1247
1248 mutex_init(&dev->fb_open_lock);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001249
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001250 /* We don't register a new USB class. Our client interface is fbdev */
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001251
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001252 /* allocates framebuffer driver structure, not framebuffer memory */
1253 info = framebuffer_alloc(0, &usbdev->dev);
1254 if (!info) {
1255 retval = -ENOMEM;
1256 dl_err("framebuffer_alloc failed\n");
1257 goto error;
1258 }
Bernie Thompson59277b62009-11-24 15:52:21 -08001259 dev->info = info;
1260 info->par = dev;
1261 info->pseudo_palette = dev->pseudo_palette;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001262 info->fbops = &dlfb_ops;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001263
Bernie Thompson59277b62009-11-24 15:52:21 -08001264 var = &info->var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001265
1266 /* TODO set limit based on actual SKU detection */
1267 dev->sku_pixel_limit = 2048 * 1152;
1268
1269 INIT_LIST_HEAD(&info->modelist);
1270 dlfb_parse_edid(dev, var, info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001271
Bernie Thompson59277b62009-11-24 15:52:21 -08001272 /*
1273 * ok, now that we've got the size info, we can alloc our framebuffer.
Bernie Thompson59277b62009-11-24 15:52:21 -08001274 */
Bernie Thompson59277b62009-11-24 15:52:21 -08001275 info->fix = dlfb_fix;
1276 info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
1277 videomemorysize = info->fix.line_length * var->yres;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001278
Bernie Thompson59277b62009-11-24 15:52:21 -08001279 /*
1280 * The big chunk of system memory we use as a virtual framebuffer.
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001281 * TODO: Handle fbcon cursor code calling blit in interrupt context
Bernie Thompson59277b62009-11-24 15:52:21 -08001282 */
1283 videomemory = vmalloc(videomemorysize);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001284 if (!videomemory) {
1285 retval = -ENOMEM;
1286 dl_err("Virtual framebuffer alloc failed\n");
1287 goto error;
1288 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001289
Bernie Thompson59277b62009-11-24 15:52:21 -08001290 info->screen_base = videomemory;
1291 info->fix.smem_len = PAGE_ALIGN(videomemorysize);
1292 info->fix.smem_start = (unsigned long) videomemory;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001293 info->flags = udlfb_info_flags;
1294
Bernie Thompson59277b62009-11-24 15:52:21 -08001295
1296 /*
1297 * Second framebuffer copy, mirroring the state of the framebuffer
1298 * on the physical USB device. We can function without this.
1299 * But with imperfect damage info we may end up sending pixels over USB
1300 * that were, in fact, unchanged -- wasting limited USB bandwidth
1301 */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001302 dev->backing_buffer = vmalloc(videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001303 if (!dev->backing_buffer)
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001304 dl_warn("No shadow/backing buffer allcoated\n");
1305 else
1306 memset(dev->backing_buffer, 0, videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001307
1308 retval = fb_alloc_cmap(&info->cmap, 256, 0);
1309 if (retval < 0) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001310 dl_err("fb_alloc_cmap failed %x\n", retval);
1311 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001312 }
1313
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001314 /* ready to begin using device */
1315
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001316#ifdef CONFIG_FB_DEFERRED_IO
1317 atomic_set(&dev->use_defio, 1);
1318#endif
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001319 atomic_set(&dev->usb_active, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -08001320 dlfb_select_std_channel(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001321
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001322 dlfb_ops_check_var(var, info);
1323 dlfb_ops_set_par(info);
1324
1325 /* paint greenscreen */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001326 pix_framebuffer = (u16 *) videomemory;
1327 for (i = 0; i < videomemorysize / 2; i++)
1328 pix_framebuffer[i] = 0x37e6;
1329
1330 dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
1331 videomemory);
Bernie Thompson530f43a2010-02-15 06:46:21 -08001332
Bernie Thompson59277b62009-11-24 15:52:21 -08001333 retval = register_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001334 if (retval < 0) {
1335 dl_err("register_framebuffer failed %d\n", retval);
1336 goto error;
1337 }
1338 registered = 1;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001339
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001340 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1341 device_create_file(info->dev, &fb_device_attrs[i]);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -07001342
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001343 device_create_bin_file(info->dev, &edid_attr);
1344
1345 dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
1346 " Using %dK framebuffer memory\n", info->node,
1347 var->xres, var->yres,
1348 ((dev->backing_buffer) ?
1349 videomemorysize * 2 : videomemorysize) >> 10);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001350 return 0;
1351
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001352error:
1353 if (dev) {
1354 if (registered) {
1355 unregister_framebuffer(info);
1356 dlfb_ops_destroy(info);
1357 } else
1358 kref_put(&dev->kref, dlfb_delete);
1359
1360 if (dev->urbs.count > 0)
1361 dlfb_free_urb_list(dev);
1362 kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
1363
1364 /* dev has been deallocated. Do not dereference */
1365 }
1366
Bernie Thompson59277b62009-11-24 15:52:21 -08001367 return retval;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001368}
1369
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001370static void dlfb_usb_disconnect(struct usb_interface *interface)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001371{
Bernie Thompson59277b62009-11-24 15:52:21 -08001372 struct dlfb_data *dev;
1373 struct fb_info *info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001374 int i;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001375
Bernie Thompson59277b62009-11-24 15:52:21 -08001376 dev = usb_get_intfdata(interface);
Bernie Thompson59277b62009-11-24 15:52:21 -08001377 info = dev->info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001378
1379 /* when non-active we'll update virtual framebuffer, but no new urbs */
1380 atomic_set(&dev->usb_active, 0);
1381
1382 usb_set_intfdata(interface, NULL);
1383
1384 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1385 device_remove_file(info->dev, &fb_device_attrs[i]);
1386
1387 device_remove_bin_file(info->dev, &edid_attr);
1388
1389 /* this function will wait for all in-flight urbs to complete */
1390 dlfb_free_urb_list(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001391
Bernie Thompson59277b62009-11-24 15:52:21 -08001392 if (info) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001393 dl_notice("Detaching /dev/fb%d\n", info->node);
Bernie Thompson59277b62009-11-24 15:52:21 -08001394 unregister_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001395 dlfb_ops_destroy(info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001396 }
1397
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001398 /* release reference taken by kref_init in probe() */
1399 kref_put(&dev->kref, dlfb_delete);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001400
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001401 /* consider dlfb_data freed */
1402
1403 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001404}
1405
1406static struct usb_driver dlfb_driver = {
1407 .name = "udlfb",
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001408 .probe = dlfb_usb_probe,
1409 .disconnect = dlfb_usb_disconnect,
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001410 .id_table = id_table,
1411};
1412
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001413static int __init dlfb_module_init(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001414{
1415 int res;
1416
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001417 res = usb_register(&dlfb_driver);
1418 if (res)
1419 err("usb_register failed. Error number %d", res);
1420
1421 printk("VMODES initialized\n");
1422
1423 return res;
1424}
1425
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001426static void __exit dlfb_module_exit(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001427{
1428 usb_deregister(&dlfb_driver);
1429}
1430
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001431module_init(dlfb_module_init);
1432module_exit(dlfb_module_exit);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001433
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001434static void dlfb_urb_completion(struct urb *urb)
1435{
1436 struct urb_node *unode = urb->context;
1437 struct dlfb_data *dev = unode->dev;
1438 unsigned long flags;
1439
1440 /* sync/async unlink faults aren't errors */
1441 if (urb->status) {
1442 if (!(urb->status == -ENOENT ||
1443 urb->status == -ECONNRESET ||
1444 urb->status == -ESHUTDOWN)) {
1445 dl_err("%s - nonzero write bulk status received: %d\n",
1446 __func__, urb->status);
1447 atomic_set(&dev->lost_pixels, 1);
1448 }
1449 }
1450
1451 urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
1452
1453 spin_lock_irqsave(&dev->urbs.lock, flags);
1454 list_add_tail(&unode->entry, &dev->urbs.list);
1455 dev->urbs.available++;
1456 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1457
1458 up(&dev->urbs.limit_sem);
1459}
1460
1461static void dlfb_free_urb_list(struct dlfb_data *dev)
1462{
1463 int count = dev->urbs.count;
1464 struct list_head *node;
1465 struct urb_node *unode;
1466 struct urb *urb;
1467 int ret;
1468 unsigned long flags;
1469
1470 dl_notice("Waiting for completes and freeing all render urbs\n");
1471
1472 /* keep waiting and freeing, until we've got 'em all */
1473 while (count--) {
1474 /* Timeout means a memory leak and/or fault */
1475 ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
1476 if (ret) {
1477 BUG_ON(ret);
1478 break;
1479 }
1480 spin_lock_irqsave(&dev->urbs.lock, flags);
1481
1482 node = dev->urbs.list.next; /* have reserved one with sem */
1483 list_del_init(node);
1484
1485 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1486
1487 unode = list_entry(node, struct urb_node, entry);
1488 urb = unode->urb;
1489
1490 /* Free each separately allocated piece */
1491 usb_buffer_free(urb->dev, dev->urbs.size,
1492 urb->transfer_buffer, urb->transfer_dma);
1493 usb_free_urb(urb);
1494 kfree(node);
1495 }
1496
1497 kref_put(&dev->kref, dlfb_delete);
1498
1499}
1500
1501static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
1502{
1503 int i = 0;
1504 struct urb *urb;
1505 struct urb_node *unode;
1506 char *buf;
1507
1508 spin_lock_init(&dev->urbs.lock);
1509
1510 dev->urbs.size = size;
1511 INIT_LIST_HEAD(&dev->urbs.list);
1512
1513 while (i < count) {
1514 unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
1515 if (!unode)
1516 break;
1517 unode->dev = dev;
1518
1519 urb = usb_alloc_urb(0, GFP_KERNEL);
1520 if (!urb) {
1521 kfree(unode);
1522 break;
1523 }
1524 unode->urb = urb;
1525
1526 buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
1527 &urb->transfer_dma);
1528 if (!buf) {
1529 kfree(unode);
1530 usb_free_urb(urb);
1531 break;
1532 }
1533
1534 /* urb->transfer_buffer_length set to actual before submit */
1535 usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
1536 buf, size, dlfb_urb_completion, unode);
1537 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1538
1539 list_add_tail(&unode->entry, &dev->urbs.list);
1540
1541 i++;
1542 }
1543
1544 sema_init(&dev->urbs.limit_sem, i);
1545 dev->urbs.count = i;
1546 dev->urbs.available = i;
1547
1548 kref_get(&dev->kref); /* released in free_render_urbs() */
1549
1550 dl_notice("allocated %d %d byte urbs \n", i, (int) size);
1551
1552 return i;
1553}
1554
1555static struct urb *dlfb_get_urb(struct dlfb_data *dev)
1556{
1557 int ret = 0;
1558 struct list_head *entry;
1559 struct urb_node *unode;
1560 struct urb *urb = NULL;
1561 unsigned long flags;
1562
1563 /* Wait for an in-flight buffer to complete and get re-queued */
1564 ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
1565 if (ret) {
1566 atomic_set(&dev->lost_pixels, 1);
1567 dl_err("wait for urb interrupted: %x\n", ret);
1568 goto error;
1569 }
1570
1571 spin_lock_irqsave(&dev->urbs.lock, flags);
1572
1573 BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
1574 entry = dev->urbs.list.next;
1575 list_del_init(entry);
1576 dev->urbs.available--;
1577
1578 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1579
1580 unode = list_entry(entry, struct urb_node, entry);
1581 urb = unode->urb;
1582
1583error:
1584 return urb;
1585}
1586
1587static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
1588{
1589 int ret;
1590
1591 BUG_ON(len > dev->urbs.size);
1592
1593 urb->transfer_buffer_length = len; /* set to actual payload len */
1594 ret = usb_submit_urb(urb, GFP_KERNEL);
1595 if (ret) {
1596 dlfb_urb_completion(urb); /* because no one else will */
1597 atomic_set(&dev->lost_pixels, 1);
1598 dl_err("usb_submit_urb error %x\n", ret);
1599 }
1600 return ret;
1601}
1602
Bernie Thompson59277b62009-11-24 15:52:21 -08001603MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001604 "Jaya Kumar <jayakumar.lkml@gmail.com>, "
1605 "Bernie Thompson <bernie@plugable.com>");
1606MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001607MODULE_LICENSE("GPL");
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001608