blob: 22f3dc310ff2948ae9796693064f7fdfe2d6bf12 [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 Thompson59277b62009-11-24 15:52:21 -080066/*
67 * Inserts a specific DisplayLink controller command into the provided
68 * buffer.
69 */
Bernie Thompson45742032010-02-15 06:46:04 -080070static char *dlfb_set_register(char *buf, u8 reg, u8 val)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070071{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080072 *buf++ = 0xAF;
73 *buf++ = 0x20;
74 *buf++ = reg;
75 *buf++ = val;
76 return buf;
Roberto De Ioris88e58b12009-06-03 14:03:06 -070077}
78
Bernie Thompson45742032010-02-15 06:46:04 -080079static char *dlfb_vidreg_lock(char *buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070080{
Bernie Thompson45742032010-02-15 06:46:04 -080081 return dlfb_set_register(buf, 0xFF, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -080082}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070083
Bernie Thompson45742032010-02-15 06:46:04 -080084static char *dlfb_vidreg_unlock(char *buf)
Bernie Thompson59277b62009-11-24 15:52:21 -080085{
Bernie Thompson45742032010-02-15 06:46:04 -080086 return dlfb_set_register(buf, 0xFF, 0xFF);
Bernie Thompson59277b62009-11-24 15:52:21 -080087}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070088
Bernie Thompson59277b62009-11-24 15:52:21 -080089/*
Bernie Thompson530f43a2010-02-15 06:46:21 -080090 * On/Off for driving the DisplayLink framebuffer to the display
Bernie Thompson59277b62009-11-24 15:52:21 -080091 */
Bernie Thompson530f43a2010-02-15 06:46:21 -080092static char *dlfb_enable_hvsync(char *buf, bool enable)
Bernie Thompson59277b62009-11-24 15:52:21 -080093{
Bernie Thompson530f43a2010-02-15 06:46:21 -080094 if (enable)
95 return dlfb_set_register(buf, 0x1F, 0x00);
96 else
97 return dlfb_set_register(buf, 0x1F, 0x01);
Bernie Thompson59277b62009-11-24 15:52:21 -080098}
99
Bernie Thompson45742032010-02-15 06:46:04 -0800100static char *dlfb_set_color_depth(char *buf, u8 selection)
Bernie Thompson59277b62009-11-24 15:52:21 -0800101{
Bernie Thompson45742032010-02-15 06:46:04 -0800102 return dlfb_set_register(buf, 0x00, selection);
Bernie Thompson59277b62009-11-24 15:52:21 -0800103}
104
Bernie Thompson45742032010-02-15 06:46:04 -0800105static char *dlfb_set_base16bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800106{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800107 /* the base pointer is 16 bits wide, 0x20 is hi byte. */
Bernie Thompson45742032010-02-15 06:46:04 -0800108 wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
109 wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
110 return dlfb_set_register(wrptr, 0x22, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800111}
112
Bernie Thompson45742032010-02-15 06:46:04 -0800113static char *dlfb_set_base8bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800114{
Bernie Thompson45742032010-02-15 06:46:04 -0800115 wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
116 wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
117 return dlfb_set_register(wrptr, 0x28, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800118}
119
Bernie Thompson45742032010-02-15 06:46:04 -0800120static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800121{
Bernie Thompson45742032010-02-15 06:46:04 -0800122 wrptr = dlfb_set_register(wrptr, reg, value >> 8);
123 return dlfb_set_register(wrptr, reg+1, value);
Bernie Thompson59277b62009-11-24 15:52:21 -0800124}
125
126/*
127 * This is kind of weird because the controller takes some
128 * register values in a different byte order than other registers.
129 */
Bernie Thompson45742032010-02-15 06:46:04 -0800130static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800131{
Bernie Thompson45742032010-02-15 06:46:04 -0800132 wrptr = dlfb_set_register(wrptr, reg, value);
133 return dlfb_set_register(wrptr, reg+1, value >> 8);
Bernie Thompson59277b62009-11-24 15:52:21 -0800134}
135
136/*
137 * LFSR is linear feedback shift register. The reason we have this is
138 * because the display controller needs to minimize the clock depth of
139 * various counters used in the display path. So this code reverses the
140 * provided value into the lfsr16 value by counting backwards to get
141 * the value that needs to be set in the hardware comparator to get the
142 * same actual count. This makes sense once you read above a couple of
143 * times and think about it from a hardware perspective.
144 */
145static u16 lfsr16(u16 actual_count)
146{
147 u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
148
149 while (actual_count--) {
150 lv = ((lv << 1) |
151 (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
152 & 0xFFFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700153 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800154
155 return (u16) lv;
156}
157
158/*
159 * This does LFSR conversion on the value that is to be written.
160 * See LFSR explanation above for more detail.
161 */
Bernie Thompson45742032010-02-15 06:46:04 -0800162static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800163{
Bernie Thompson45742032010-02-15 06:46:04 -0800164 return dlfb_set_register_16(wrptr, reg, lfsr16(value));
Bernie Thompson59277b62009-11-24 15:52:21 -0800165}
166
167/*
168 * This takes a standard fbdev screeninfo struct and all of its monitor mode
169 * details and converts them into the DisplayLink equivalent register commands.
170 */
Bernie Thompson45742032010-02-15 06:46:04 -0800171static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
Bernie Thompson59277b62009-11-24 15:52:21 -0800172{
173 u16 xds, yds;
174 u16 xde, yde;
175 u16 yec;
176
Bernie Thompson59277b62009-11-24 15:52:21 -0800177 /* x display start */
178 xds = var->left_margin + var->hsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800179 wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800180 /* x display end */
181 xde = xds + var->xres;
Bernie Thompson45742032010-02-15 06:46:04 -0800182 wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800183
184 /* y display start */
185 yds = var->upper_margin + var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800186 wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800187 /* y display end */
188 yde = yds + var->yres;
Bernie Thompson45742032010-02-15 06:46:04 -0800189 wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800190
191 /* x end count is active + blanking - 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800192 wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
193 xde + var->right_margin - 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800194
195 /* libdlo hardcodes hsync start to 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800196 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800197
198 /* hsync end is width of sync pulse + 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800199 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800200
201 /* hpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800202 wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800203
204 /* yendcount is vertical active + vertical blanking */
205 yec = var->yres + var->upper_margin + var->lower_margin +
206 var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800207 wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
Bernie Thompson59277b62009-11-24 15:52:21 -0800208
209 /* libdlo hardcodes vsync start to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800210 wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800211
212 /* vsync end is width of vsync pulse */
Bernie Thompson45742032010-02-15 06:46:04 -0800213 wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800214
215 /* vpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800216 wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800217
218 /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
Bernie Thompson45742032010-02-15 06:46:04 -0800219 wrptr = dlfb_set_register_16be(wrptr, 0x1B,
220 200*1000*1000/var->pixclock);
Bernie Thompson59277b62009-11-24 15:52:21 -0800221
222 return wrptr;
223}
224
225/*
226 * This takes a standard fbdev screeninfo struct that was fetched or prepared
227 * and then generates the appropriate command sequence that then drives the
228 * display controller.
229 */
230static int dlfb_set_video_mode(struct dlfb_data *dev,
231 struct fb_var_screeninfo *var)
232{
233 char *buf;
234 char *wrptr;
235 int retval = 0;
236 int writesize;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800237 struct urb *urb;
Bernie Thompson59277b62009-11-24 15:52:21 -0800238
Bernie Thompson530f43a2010-02-15 06:46:21 -0800239 if (!atomic_read(&dev->usb_active))
240 return -EPERM;
241
242 urb = dlfb_get_urb(dev);
243 if (!urb)
244 return -ENOMEM;
245 buf = (char *) urb->transfer_buffer;
Bernie Thompson59277b62009-11-24 15:52:21 -0800246
247 /*
248 * This first section has to do with setting the base address on the
249 * controller * associated with the display. There are 2 base
250 * pointers, currently, we only * use the 16 bpp segment.
251 */
Bernie Thompson45742032010-02-15 06:46:04 -0800252 wrptr = dlfb_vidreg_lock(buf);
253 wrptr = dlfb_set_color_depth(wrptr, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -0800254 /* set base for 16bpp segment to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800255 wrptr = dlfb_set_base16bpp(wrptr, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800256 /* set base for 8bpp segment to end of fb */
Bernie Thompson45742032010-02-15 06:46:04 -0800257 wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800258
Bernie Thompson45742032010-02-15 06:46:04 -0800259 wrptr = dlfb_set_vid_cmds(wrptr, var);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800260 wrptr = dlfb_enable_hvsync(wrptr, true);
Bernie Thompson45742032010-02-15 06:46:04 -0800261 wrptr = dlfb_vidreg_unlock(wrptr);
Bernie Thompson59277b62009-11-24 15:52:21 -0800262
263 writesize = wrptr - buf;
264
Bernie Thompson530f43a2010-02-15 06:46:21 -0800265 retval = dlfb_submit_urb(dev, urb, writesize);
Bernie Thompson59277b62009-11-24 15:52:21 -0800266
Bernie Thompson59277b62009-11-24 15:52:21 -0800267 return retval;
268}
269
Bernie Thompson45742032010-02-15 06:46:04 -0800270static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700271{
272 unsigned long start = vma->vm_start;
273 unsigned long size = vma->vm_end - vma->vm_start;
274 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
275 unsigned long page, pos;
276
277 printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
278
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700279 if (offset + size > info->fix.smem_len)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700280 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700281
282 pos = (unsigned long)info->fix.smem_start + offset;
283
284 while (size > 0) {
285 page = vmalloc_to_pfn((void *)pos);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700286 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700287 return -EAGAIN;
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700288
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700289 start += PAGE_SIZE;
290 pos += PAGE_SIZE;
291 if (size > PAGE_SIZE)
292 size -= PAGE_SIZE;
293 else
294 size = 0;
295 }
296
297 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
298 return 0;
299
300}
301
Bernie Thompson530f43a2010-02-15 06:46:21 -0800302/*
303 * Trims identical data from front and back of line
304 * Sets new front buffer address and width
305 * And returns byte count of identical pixels
306 * Assumes CPU natural alignment (unsigned long)
307 * for back and front buffer ptrs and width
308 */
309static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700310{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800311 int j, k;
312 const unsigned long *back = (const unsigned long *) bback;
313 const unsigned long *front = (const unsigned long *) *bfront;
314 const int width = *width_bytes / sizeof(unsigned long);
315 int identical = width;
316 int start = width;
317 int end = width;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700318
Bernie Thompson530f43a2010-02-15 06:46:21 -0800319 prefetch((void *) front);
320 prefetch((void *) back);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700321
Bernie Thompson530f43a2010-02-15 06:46:21 -0800322 for (j = 0; j < width; j++) {
323 if (back[j] != front[j]) {
324 start = j;
325 break;
326 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700327 }
328
Bernie Thompson530f43a2010-02-15 06:46:21 -0800329 for (k = width - 1; k > j; k--) {
330 if (back[k] != front[k]) {
331 end = k+1;
332 break;
333 }
334 }
335
336 identical = start + (width - end);
337 *bfront = (u8 *) &front[start];
338 *width_bytes = (end - start) * sizeof(unsigned long);
339
340 return identical * sizeof(unsigned long);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700341}
342
343/*
Bernie Thompson530f43a2010-02-15 06:46:21 -0800344Render a command stream for an encoded horizontal line segment of pixels.
345
346A command buffer holds several commands.
347It always begins with a fresh command header
348(the protocol doesn't require this, but we enforce it to allow
349multiple buffers to be potentially encoded and sent in parallel).
350A single command encodes one contiguous horizontal line of pixels
351
352The function relies on the client to do all allocation, so that
353rendering can be done directly to output buffers (e.g. USB URBs).
354The function fills the supplied command buffer, providing information
355on where it left off, so the client may call in again with additional
356buffers if the line will take several buffers to complete.
357
358A single command can transmit a maximum of 256 pixels,
359regardless of the compression ratio (protocol design limit).
360To the hardware, 0 for a size byte means 256
361
362Rather than 256 pixel commands which are either rl or raw encoded,
363the rlx command simply assumes alternating raw and rl spans within one cmd.
364This has a slightly larger header overhead, but produces more even results.
365It also processes all data (read and write) in a single pass.
366Performance benchmarks of common cases show it having just slightly better
367compression than 256 pixel raw -or- rle commands, with similar CPU consumpion.
368But for very rl friendly data, will compress not quite as well.
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700369*/
Bernie Thompson530f43a2010-02-15 06:46:21 -0800370static void dlfb_compress_hline(
371 const uint16_t **pixel_start_ptr,
372 const uint16_t *const pixel_end,
373 uint32_t *device_address_ptr,
374 uint8_t **command_buffer_ptr,
375 const uint8_t *const cmd_buffer_end)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700376{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800377 const uint16_t *pixel = *pixel_start_ptr;
378 uint32_t dev_addr = *device_address_ptr;
379 uint8_t *cmd = *command_buffer_ptr;
380 const int bpp = 2;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700381
Bernie Thompson530f43a2010-02-15 06:46:21 -0800382 while ((pixel_end > pixel) &&
383 (cmd_buffer_end - MIN_RLX_CMD_BYTES > cmd)) {
384 uint8_t *raw_pixels_count_byte = 0;
385 uint8_t *cmd_pixels_count_byte = 0;
386 const uint16_t *raw_pixel_start = 0;
387 const uint16_t *cmd_pixel_start, *cmd_pixel_end = 0;
388 const uint32_t be_dev_addr = cpu_to_be32(dev_addr);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700389
Bernie Thompson530f43a2010-02-15 06:46:21 -0800390 prefetchw((void *) cmd); /* pull in one cache line at least */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700391
Bernie Thompson530f43a2010-02-15 06:46:21 -0800392 *cmd++ = 0xAF;
393 *cmd++ = 0x6B;
394 *cmd++ = (uint8_t) ((be_dev_addr >> 8) & 0xFF);
395 *cmd++ = (uint8_t) ((be_dev_addr >> 16) & 0xFF);
396 *cmd++ = (uint8_t) ((be_dev_addr >> 24) & 0xFF);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700397
Bernie Thompson530f43a2010-02-15 06:46:21 -0800398 cmd_pixels_count_byte = cmd++; /* we'll know this later */
399 cmd_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700400
Bernie Thompson530f43a2010-02-15 06:46:21 -0800401 raw_pixels_count_byte = cmd++; /* we'll know this later */
402 raw_pixel_start = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700403
Bernie Thompson530f43a2010-02-15 06:46:21 -0800404 cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1,
405 min((int)(pixel_end - pixel),
406 (int)(cmd_buffer_end - cmd) / bpp));
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700407
Bernie Thompson530f43a2010-02-15 06:46:21 -0800408 prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700409
Bernie Thompson530f43a2010-02-15 06:46:21 -0800410 while (pixel < cmd_pixel_end) {
411 const uint16_t * const repeating_pixel = pixel;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700412
Bernie Thompson530f43a2010-02-15 06:46:21 -0800413 *(uint16_t *)cmd = cpu_to_be16p(pixel);
414 cmd += 2;
415 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700416
Bernie Thompson530f43a2010-02-15 06:46:21 -0800417 if (unlikely((pixel < cmd_pixel_end) &&
418 (*pixel == *repeating_pixel))) {
419 /* go back and fill in raw pixel count */
420 *raw_pixels_count_byte = ((repeating_pixel -
421 raw_pixel_start) + 1) & 0xFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700422
Bernie Thompson530f43a2010-02-15 06:46:21 -0800423 while ((pixel < cmd_pixel_end)
424 && (*pixel == *repeating_pixel)) {
425 pixel++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700426 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800427
Bernie Thompson530f43a2010-02-15 06:46:21 -0800428 /* immediately after raw data is repeat byte */
429 *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF;
Bernie Thompson59277b62009-11-24 15:52:21 -0800430
Bernie Thompson530f43a2010-02-15 06:46:21 -0800431 /* Then start another raw pixel span */
432 raw_pixel_start = pixel;
433 raw_pixels_count_byte = cmd++;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700434 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700435 }
436
Bernie Thompson530f43a2010-02-15 06:46:21 -0800437 if (pixel > raw_pixel_start) {
438 /* finalize last RAW span */
439 *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF;
440 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700441
Bernie Thompson530f43a2010-02-15 06:46:21 -0800442 *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF;
443 dev_addr += (pixel - cmd_pixel_start) * bpp;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700444 }
445
Bernie Thompson530f43a2010-02-15 06:46:21 -0800446 if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) {
447 /* Fill leftover bytes with no-ops */
448 if (cmd_buffer_end > cmd)
449 memset(cmd, 0xAF, cmd_buffer_end - cmd);
450 cmd = (uint8_t *) cmd_buffer_end;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700451 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700452
Bernie Thompson530f43a2010-02-15 06:46:21 -0800453 *command_buffer_ptr = cmd;
454 *pixel_start_ptr = pixel;
455 *device_address_ptr = dev_addr;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700456
Bernie Thompson530f43a2010-02-15 06:46:21 -0800457 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700458}
459
Bernie Thompson530f43a2010-02-15 06:46:21 -0800460/*
461 * There are 3 copies of every pixel: The front buffer that the fbdev
462 * client renders to, the actual framebuffer across the USB bus in hardware
463 * (that we can only write to, slowly, and can never read), and (optionally)
464 * our shadow copy that tracks what's been sent to that hardware buffer.
465 */
466static void dlfb_render_hline(struct dlfb_data *dev, struct urb **urb_ptr,
467 const char *front, char **urb_buf_ptr,
468 u32 byte_offset, u32 byte_width,
469 int *ident_ptr, int *sent_ptr)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700470{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800471 const u8 *line_start, *line_end, *next_pixel;
472 u32 dev_addr = dev->base16 + byte_offset;
473 struct urb *urb = *urb_ptr;
474 u8 *cmd = *urb_buf_ptr;
475 u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700476
Bernie Thompson530f43a2010-02-15 06:46:21 -0800477 line_start = (u8 *) (front + byte_offset);
478 next_pixel = line_start;
479 line_end = next_pixel + byte_width;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700480
Bernie Thompson530f43a2010-02-15 06:46:21 -0800481 if (dev->backing_buffer) {
482 int offset;
483 const u8 *back_start = (u8 *) (dev->backing_buffer
484 + byte_offset);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700485
Bernie Thompson530f43a2010-02-15 06:46:21 -0800486 *ident_ptr += dlfb_trim_hline(back_start, &next_pixel,
487 &byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700488
Bernie Thompson530f43a2010-02-15 06:46:21 -0800489 offset = next_pixel - line_start;
490 line_end = next_pixel + byte_width;
491 dev_addr += offset;
492 back_start += offset;
493 line_start += offset;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700494
Bernie Thompson530f43a2010-02-15 06:46:21 -0800495 memcpy((char *)back_start, (char *) line_start,
496 byte_width);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700497 }
498
Bernie Thompson530f43a2010-02-15 06:46:21 -0800499 while (next_pixel < line_end) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700500
Bernie Thompson530f43a2010-02-15 06:46:21 -0800501 dlfb_compress_hline((const uint16_t **) &next_pixel,
502 (const uint16_t *) line_end, &dev_addr,
503 (u8 **) &cmd, (u8 *) cmd_end);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700504
Bernie Thompson530f43a2010-02-15 06:46:21 -0800505 if (cmd >= cmd_end) {
506 int len = cmd - (u8 *) urb->transfer_buffer;
507 if (dlfb_submit_urb(dev, urb, len))
508 return; /* lost pixels is set */
509 *sent_ptr += len;
510 urb = dlfb_get_urb(dev);
511 if (!urb)
512 return; /* lost_pixels is set */
513 *urb_ptr = urb;
514 cmd = urb->transfer_buffer;
515 cmd_end = &cmd[urb->transfer_buffer_length];
516 }
517 }
518
519 *urb_buf_ptr = cmd;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700520}
521
Bernie Thompson530f43a2010-02-15 06:46:21 -0800522int dlfb_handle_damage(struct dlfb_data *dev, int x, int y,
523 int width, int height, char *data)
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700524{
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700525 int i, ret;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800526 char *cmd;
527 cycles_t start_cycles, end_cycles;
528 int bytes_sent = 0;
529 int bytes_identical = 0;
530 struct urb *urb;
531 int aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700532
Bernie Thompson530f43a2010-02-15 06:46:21 -0800533 start_cycles = get_cycles();
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700534
Bernie Thompson530f43a2010-02-15 06:46:21 -0800535 aligned_x = DL_ALIGN_DOWN(x, sizeof(unsigned long));
536 width = DL_ALIGN_UP(width + (x-aligned_x), sizeof(unsigned long));
537 x = aligned_x;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700538
Bernie Thompson530f43a2010-02-15 06:46:21 -0800539 if ((width <= 0) ||
540 (x + width > dev->info->var.xres) ||
541 (y + height > dev->info->var.yres))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700542 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700543
Bernie Thompson530f43a2010-02-15 06:46:21 -0800544 if (!atomic_read(&dev->usb_active))
545 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700546
Bernie Thompson530f43a2010-02-15 06:46:21 -0800547 urb = dlfb_get_urb(dev);
548 if (!urb)
549 return 0;
550 cmd = urb->transfer_buffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700551
Bernie Thompson530f43a2010-02-15 06:46:21 -0800552 for (i = y; i < y + height ; i++) {
553 const int line_offset = dev->info->fix.line_length * i;
554 const int byte_offset = line_offset + (x * BPP);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700555
Bernie Thompson530f43a2010-02-15 06:46:21 -0800556 dlfb_render_hline(dev, &urb, (char *) dev->info->fix.smem_start,
557 &cmd, byte_offset, width * BPP,
558 &bytes_identical, &bytes_sent);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700559 }
560
Bernie Thompson530f43a2010-02-15 06:46:21 -0800561 if (cmd > (char *) urb->transfer_buffer) {
562 /* Send partial buffer remaining before exiting */
563 int len = cmd - (char *) urb->transfer_buffer;
564 ret = dlfb_submit_urb(dev, urb, len);
565 bytes_sent += len;
566 } else
567 dlfb_urb_completion(urb);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700568
Bernie Thompson530f43a2010-02-15 06:46:21 -0800569 atomic_add(bytes_sent, &dev->bytes_sent);
570 atomic_add(bytes_identical, &dev->bytes_identical);
571 atomic_add(width*height*2, &dev->bytes_rendered);
572 end_cycles = get_cycles();
573 atomic_add(((unsigned int) ((end_cycles - start_cycles)
574 >> 10)), /* Kcycles */
575 &dev->cpu_kcycles_used);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700576
Bernie Thompson530f43a2010-02-15 06:46:21 -0800577 return 0;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700578}
579
Bernie Thompson530f43a2010-02-15 06:46:21 -0800580/* hardware has native COPY command (see libdlo), but not worth it for fbcon */
Bernie Thompson45742032010-02-15 06:46:04 -0800581static void dlfb_ops_copyarea(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800582 const struct fb_copyarea *area)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700583{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800584
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700585 struct dlfb_data *dev = info->par;
586
Bernie Thompson530f43a2010-02-15 06:46:21 -0800587#if defined CONFIG_FB_SYS_COPYAREA || defined CONFIG_FB_SYS_COPYAREA_MODULE
588
589 sys_copyarea(info, area);
590
591 dlfb_handle_damage(dev, area->dx, area->dy,
592 area->width, area->height, info->screen_base);
593#endif
594 atomic_inc(&dev->copy_count);
595
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700596}
597
Bernie Thompson45742032010-02-15 06:46:04 -0800598static void dlfb_ops_imageblit(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800599 const struct fb_image *image)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700600{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700601 struct dlfb_data *dev = info->par;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800602
603#if defined CONFIG_FB_SYS_IMAGEBLIT || defined CONFIG_FB_SYS_IMAGEBLIT_MODULE
604
605 sys_imageblit(info, image);
606
607 dlfb_handle_damage(dev, image->dx, image->dy,
608 image->width, image->height, info->screen_base);
609
610#endif
611
612 atomic_inc(&dev->blit_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700613}
614
Bernie Thompson45742032010-02-15 06:46:04 -0800615static void dlfb_ops_fillrect(struct fb_info *info,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800616 const struct fb_fillrect *rect)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700617{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700618 struct dlfb_data *dev = info->par;
619
Bernie Thompson530f43a2010-02-15 06:46:21 -0800620#if defined CONFIG_FB_SYS_FILLRECT || defined CONFIG_FB_SYS_FILLRECT_MODULE
621
622 sys_fillrect(info, rect);
623
624 dlfb_handle_damage(dev, rect->dx, rect->dy, rect->width,
625 rect->height, info->screen_base);
626#endif
627
628 atomic_inc(&dev->fill_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700629
630}
631
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800632static void dlfb_get_edid(struct dlfb_data *dev)
633{
634 int i;
635 int ret;
636 char rbuf[2];
637
638 for (i = 0; i < sizeof(dev->edid); i++) {
639 ret = usb_control_msg(dev->udev,
640 usb_rcvctrlpipe(dev->udev, 0), (0x02),
641 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
642 0);
643 dev->edid[i] = rbuf[1];
644 }
645}
646
Bernie Thompson45742032010-02-15 06:46:04 -0800647static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
Bernie Thompson530f43a2010-02-15 06:46:21 -0800648 unsigned long arg)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700649{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800650
651 struct dlfb_data *dev = info->par;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700652 struct dloarea *area = NULL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700653
Bernie Thompson530f43a2010-02-15 06:46:21 -0800654 if (!atomic_read(&dev->usb_active))
655 return 0;
656
657 /* TODO: Update X server to get this from sysfs instead */
658 if (cmd == DLFB_IOCTL_RETURN_EDID) {
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700659 char *edid = (char *)arg;
Bernie Thompson530f43a2010-02-15 06:46:21 -0800660 dlfb_get_edid(dev);
661 if (copy_to_user(edid, dev->edid, sizeof(dev->edid)))
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700662 return -EFAULT;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700663 return 0;
664 }
665
Bernie Thompson530f43a2010-02-15 06:46:21 -0800666 /* TODO: Help propose a standard fb.h ioctl to report mmap damage */
667 if (cmd == DLFB_IOCTL_REPORT_DAMAGE) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700668
669 area = (struct dloarea *)arg;
670
671 if (area->x < 0)
672 area->x = 0;
673
674 if (area->x > info->var.xres)
675 area->x = info->var.xres;
676
677 if (area->y < 0)
678 area->y = 0;
679
680 if (area->y > info->var.yres)
681 area->y = info->var.yres;
682
Bernie Thompson530f43a2010-02-15 06:46:21 -0800683 atomic_set(&dev->use_defio, 0);
684
685 dlfb_handle_damage(dev, area->x, area->y, area->w, area->h,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700686 info->screen_base);
Bernie Thompson530f43a2010-02-15 06:46:21 -0800687 atomic_inc(&dev->damage_count);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700688 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700689
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700690 return 0;
691}
692
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700693/* taken from vesafb */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700694static int
Bernie Thompson45742032010-02-15 06:46:04 -0800695dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700696 unsigned blue, unsigned transp, struct fb_info *info)
697{
698 int err = 0;
699
700 if (regno >= info->cmap.len)
701 return 1;
702
703 if (regno < 16) {
704 if (info->var.red.offset == 10) {
705 /* 1:5:5:5 */
706 ((u32 *) (info->pseudo_palette))[regno] =
707 ((red & 0xf800) >> 1) |
708 ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
709 } else {
710 /* 0:5:6:5 */
711 ((u32 *) (info->pseudo_palette))[regno] =
712 ((red & 0xf800)) |
713 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
714 }
715 }
716
717 return err;
718}
719
Bernie Thompson45742032010-02-15 06:46:04 -0800720static int dlfb_ops_release(struct fb_info *info, int user)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700721{
722 struct dlfb_data *dev_info = info->par;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700723 return 0;
724}
725
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800726/*
727 * Called when all client interfaces to start transactions have been disabled,
728 * and all references to our device instance (dlfb_data) are released.
729 * Every transaction must have a reference, so we know are fully spun down
730 */
731static void dlfb_delete(struct kref *kref)
732{
733 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
734
735 if (dev->backing_buffer)
736 vfree(dev->backing_buffer);
737
738 kfree(dev);
739}
740
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800741/*
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800742 * Called by fbdev as last part of unregister_framebuffer() process
743 * No new clients can open connections. Deallocate everything fb_info.
744 */
745static void dlfb_ops_destroy(struct fb_info *info)
746{
747 struct dlfb_data *dev = info->par;
748
749 if (info->cmap.len != 0)
750 fb_dealloc_cmap(&info->cmap);
751 if (info->monspecs.modedb)
752 fb_destroy_modedb(info->monspecs.modedb);
753 if (info->screen_base)
754 vfree(info->screen_base);
755
756 fb_destroy_modelist(&info->modelist);
757
758 framebuffer_release(info);
759
760 /* ref taken before register_framebuffer() for dlfb_data clients */
761 kref_put(&dev->kref, dlfb_delete);
762}
763
764/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800765 * Check whether a video mode is supported by the DisplayLink chip
766 * We start from monitor's modes, so don't need to filter that here
767 */
768static int dlfb_is_valid_mode(struct fb_videomode *mode,
769 struct fb_info *info)
770{
771 struct dlfb_data *dev = info->par;
772
773 if (mode->xres * mode->yres > dev->sku_pixel_limit)
774 return 0;
775
776 return 1;
777}
778
779static void dlfb_var_color_format(struct fb_var_screeninfo *var)
780{
781 const struct fb_bitfield red = { 11, 5, 0 };
782 const struct fb_bitfield green = { 5, 6, 0 };
783 const struct fb_bitfield blue = { 0, 5, 0 };
784
785 var->bits_per_pixel = 16;
786 var->red = red;
787 var->green = green;
788 var->blue = blue;
789}
790
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800791static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
792 struct fb_info *info)
793{
794 struct fb_videomode mode;
795
796 /* TODO: support dynamically changing framebuffer size */
797 if ((var->xres * var->yres * 2) > info->fix.smem_len)
798 return -EINVAL;
799
800 /* set device-specific elements of var unrelated to mode */
801 dlfb_var_color_format(var);
802
803 fb_var_to_videomode(&mode, var);
804
805 if (!dlfb_is_valid_mode(&mode, info))
806 return -EINVAL;
807
808 return 0;
809}
810
811static int dlfb_ops_set_par(struct fb_info *info)
812{
813 struct dlfb_data *dev = info->par;
814
815 dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
816
817 return dlfb_set_video_mode(dev, &info->var);
818}
819
Bernie Thompson45742032010-02-15 06:46:04 -0800820static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700821{
Bernie Thompson530f43a2010-02-15 06:46:21 -0800822 struct dlfb_data *dev = info->par;
823 char *bufptr;
824 struct urb *urb;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700825
Bernie Thompson530f43a2010-02-15 06:46:21 -0800826 urb = dlfb_get_urb(dev);
827 if (!urb)
828 return 0;
829 bufptr = (char *) urb->transfer_buffer;
830
831 /* overloading usb_active. UNBLANK can conflict with teardown */
832
833 bufptr = dlfb_vidreg_lock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700834 if (blank_mode != FB_BLANK_UNBLANK) {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800835 atomic_set(&dev->usb_active, 0);
836 bufptr = dlfb_enable_hvsync(bufptr, false);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700837 } else {
Bernie Thompson530f43a2010-02-15 06:46:21 -0800838 atomic_set(&dev->usb_active, 1);
839 bufptr = dlfb_enable_hvsync(bufptr, true);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700840 }
Bernie Thompson530f43a2010-02-15 06:46:21 -0800841 bufptr = dlfb_vidreg_unlock(bufptr);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700842
Bernie Thompson530f43a2010-02-15 06:46:21 -0800843 dlfb_submit_urb(dev, urb, bufptr - (char *) urb->transfer_buffer);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700844
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700845 return 0;
846}
847
848static struct fb_ops dlfb_ops = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800849 .owner = THIS_MODULE,
Bernie Thompson45742032010-02-15 06:46:04 -0800850 .fb_setcolreg = dlfb_ops_setcolreg,
851 .fb_fillrect = dlfb_ops_fillrect,
852 .fb_copyarea = dlfb_ops_copyarea,
853 .fb_imageblit = dlfb_ops_imageblit,
854 .fb_mmap = dlfb_ops_mmap,
855 .fb_ioctl = dlfb_ops_ioctl,
856 .fb_release = dlfb_ops_release,
857 .fb_blank = dlfb_ops_blank,
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800858 .fb_check_var = dlfb_ops_check_var,
859 .fb_set_par = dlfb_ops_set_par,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700860};
861
Bernie Thompsoncc403dc2010-02-15 06:45:49 -0800862/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800863 * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
864 * Then parses EDID into three places used by various parts of fbdev:
865 * fb_var_screeninfo contains the timing of the monitor's preferred mode
866 * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
867 * fb_info.modelist is a linked list of all monitor & VESA modes which work
868 *
869 * If EDID is not readable/valid, then modelist is all VESA modes,
870 * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
871 * Returns 0 if EDID parses successfully
872 */
873static int dlfb_parse_edid(struct dlfb_data *dev,
874 struct fb_var_screeninfo *var,
875 struct fb_info *info)
876{
877 int i;
878 const struct fb_videomode *default_vmode = NULL;
879 int result = 0;
880
881 fb_destroy_modelist(&info->modelist);
882 memset(&info->monspecs, 0, sizeof(info->monspecs));
883
884 dlfb_get_edid(dev);
885 fb_edid_to_monspecs(dev->edid, &info->monspecs);
886
887 if (info->monspecs.modedb_len > 0) {
888
889 for (i = 0; i < info->monspecs.modedb_len; i++) {
890 if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
891 fb_add_videomode(&info->monspecs.modedb[i],
892 &info->modelist);
893 }
894
895 default_vmode = fb_find_best_display(&info->monspecs,
896 &info->modelist);
897 } else {
898 struct fb_videomode fb_vmode = {0};
899
900 dl_err("Unable to get valid EDID from device/display\n");
901 result = 1;
902
903 /*
904 * Add the standard VESA modes to our modelist
905 * Since we don't have EDID, there may be modes that
906 * overspec monitor and/or are incorrect aspect ratio, etc.
907 * But at least the user has a chance to choose
908 */
909 for (i = 0; i < VESA_MODEDB_SIZE; i++) {
910 if (dlfb_is_valid_mode((struct fb_videomode *)
911 &vesa_modes[i], info))
912 fb_add_videomode(&vesa_modes[i],
913 &info->modelist);
914 }
915
916 /*
917 * default to resolution safe for projectors
918 * (since they are most common case without EDID)
919 */
920 fb_vmode.xres = 800;
921 fb_vmode.yres = 600;
922 fb_vmode.refresh = 60;
923 default_vmode = fb_find_nearest_mode(&fb_vmode,
924 &info->modelist);
925 }
926
927 fb_videomode_to_var(var, default_vmode);
928 dlfb_var_color_format(var);
929
930 return result;
931}
932
933static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
934 struct device_attribute *a, char *buf) {
935 struct fb_info *fb_info = dev_get_drvdata(fbdev);
936 struct dlfb_data *dev = fb_info->par;
937 return snprintf(buf, PAGE_SIZE, "%u\n",
938 atomic_read(&dev->bytes_rendered));
939}
940
941static ssize_t metrics_bytes_identical_show(struct device *fbdev,
942 struct device_attribute *a, char *buf) {
943 struct fb_info *fb_info = dev_get_drvdata(fbdev);
944 struct dlfb_data *dev = fb_info->par;
945 return snprintf(buf, PAGE_SIZE, "%u\n",
946 atomic_read(&dev->bytes_identical));
947}
948
949static ssize_t metrics_bytes_sent_show(struct device *fbdev,
950 struct device_attribute *a, char *buf) {
951 struct fb_info *fb_info = dev_get_drvdata(fbdev);
952 struct dlfb_data *dev = fb_info->par;
953 return snprintf(buf, PAGE_SIZE, "%u\n",
954 atomic_read(&dev->bytes_sent));
955}
956
957static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
958 struct device_attribute *a, char *buf) {
959 struct fb_info *fb_info = dev_get_drvdata(fbdev);
960 struct dlfb_data *dev = fb_info->par;
961 return snprintf(buf, PAGE_SIZE, "%u\n",
962 atomic_read(&dev->cpu_kcycles_used));
963}
964
965static ssize_t metrics_misc_show(struct device *fbdev,
966 struct device_attribute *a, char *buf) {
967 struct fb_info *fb_info = dev_get_drvdata(fbdev);
968 struct dlfb_data *dev = fb_info->par;
969 return snprintf(buf, PAGE_SIZE,
970 "Calls to\ndamage: %u\nblit: %u\n"
971 "defio faults: %u\ncopy: %u\n"
972 "fill: %u\n\n"
973 "active framebuffer clients: %d\n"
974 "urbs available %d(%d)\n"
975 "Shadow framebuffer in use? %s\n"
976 "Any lost pixels? %s\n",
977 atomic_read(&dev->damage_count),
978 atomic_read(&dev->blit_count),
979 atomic_read(&dev->defio_fault_count),
980 atomic_read(&dev->copy_count),
981 atomic_read(&dev->fill_count),
982 dev->fb_count,
983 dev->urbs.available, dev->urbs.limit_sem.count,
984 (dev->backing_buffer) ? "yes" : "no",
985 atomic_read(&dev->lost_pixels) ? "yes" : "no");
986}
987
988static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
989 char *buf, loff_t off, size_t count) {
990 struct device *fbdev = container_of(kobj, struct device, kobj);
991 struct fb_info *fb_info = dev_get_drvdata(fbdev);
992 struct dlfb_data *dev = fb_info->par;
993 char *edid = &dev->edid[0];
994 const size_t size = sizeof(dev->edid);
995
996 if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
997 return 0;
998
999 if (off >= size)
1000 return 0;
1001
1002 if (off + count > size)
1003 count = size - off;
1004 memcpy(buf, edid + off, count);
1005
1006 return count;
1007}
1008
1009
1010static ssize_t metrics_reset_store(struct device *fbdev,
1011 struct device_attribute *attr,
1012 const char *buf, size_t count)
1013{
1014 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1015 struct dlfb_data *dev = fb_info->par;
1016
1017 atomic_set(&dev->bytes_rendered, 0);
1018 atomic_set(&dev->bytes_identical, 0);
1019 atomic_set(&dev->bytes_sent, 0);
1020 atomic_set(&dev->cpu_kcycles_used, 0);
1021 atomic_set(&dev->blit_count, 0);
1022 atomic_set(&dev->copy_count, 0);
1023 atomic_set(&dev->fill_count, 0);
1024 atomic_set(&dev->defio_fault_count, 0);
1025 atomic_set(&dev->damage_count, 0);
1026
1027 return count;
1028}
1029
1030static ssize_t use_defio_show(struct device *fbdev,
1031 struct device_attribute *a, char *buf) {
1032 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1033 struct dlfb_data *dev = fb_info->par;
1034 return snprintf(buf, PAGE_SIZE, "%d\n",
1035 atomic_read(&dev->use_defio));
1036}
1037
1038static ssize_t use_defio_store(struct device *fbdev,
1039 struct device_attribute *attr,
1040 const char *buf, size_t count)
1041{
1042 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1043 struct dlfb_data *dev = fb_info->par;
1044
1045 if (count > 0) {
1046 if (buf[0] == '0')
1047 atomic_set(&dev->use_defio, 0);
1048 if (buf[0] == '1')
1049 atomic_set(&dev->use_defio, 1);
1050 }
1051 return count;
1052}
1053
1054static struct bin_attribute edid_attr = {
1055 .attr.name = "edid",
1056 .attr.mode = 0444,
1057 .size = 128,
1058 .read = edid_show,
1059};
1060
1061static struct device_attribute fb_device_attrs[] = {
1062 __ATTR_RO(metrics_bytes_rendered),
1063 __ATTR_RO(metrics_bytes_identical),
1064 __ATTR_RO(metrics_bytes_sent),
1065 __ATTR_RO(metrics_cpu_kcycles_used),
1066 __ATTR_RO(metrics_misc),
1067 __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
1068 __ATTR_RW(use_defio),
1069};
1070
1071/*
Bernie Thompsoncc403dc2010-02-15 06:45:49 -08001072 * This is necessary before we can communicate with the display controller.
1073 */
1074static int dlfb_select_std_channel(struct dlfb_data *dev)
1075{
1076 int ret;
1077 u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7,
1078 0x1C, 0x88, 0x5E, 0x15,
1079 0x60, 0xFE, 0xC6, 0x97,
1080 0x16, 0x3D, 0x47, 0xF2 };
1081
1082 ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
1083 NR_USB_REQUEST_CHANNEL,
1084 (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
1085 set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
1086 return ret;
1087}
1088
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001089
1090static int dlfb_usb_probe(struct usb_interface *interface,
Bernie Thompson59277b62009-11-24 15:52:21 -08001091 const struct usb_device_id *id)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001092{
Bernie Thompson59277b62009-11-24 15:52:21 -08001093 struct usb_device *usbdev;
1094 struct dlfb_data *dev;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001095 struct fb_info *info;
Bernie Thompson59277b62009-11-24 15:52:21 -08001096 int videomemorysize;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001097 int i;
Bernie Thompson59277b62009-11-24 15:52:21 -08001098 unsigned char *videomemory;
1099 int retval = -ENOMEM;
1100 struct fb_var_screeninfo *var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001101 int registered = 0;
1102 u16 *pix_framebuffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001103
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001104 /* usb initialization */
1105
1106 usbdev = interface_to_usbdev(interface);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001107
Bernie Thompson59277b62009-11-24 15:52:21 -08001108 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1109 if (dev == NULL) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001110 err("dlfb_usb_probe: failed alloc of dev struct\n");
1111 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001112 }
1113
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001114 /* we need to wait for both usb and fbdev to spin down on disconnect */
1115 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
1116 kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
1117
Bernie Thompson59277b62009-11-24 15:52:21 -08001118 dev->udev = usbdev;
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001119 dev->gdev = &usbdev->dev; /* our generic struct device * */
Bernie Thompson59277b62009-11-24 15:52:21 -08001120 usb_set_intfdata(interface, dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001121
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001122 if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
1123 retval = -ENOMEM;
1124 dl_err("dlfb_alloc_urb_list failed\n");
1125 goto error;
1126 }
1127
1128 mutex_init(&dev->fb_open_lock);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001129
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001130 /* We don't register a new USB class. Our client interface is fbdev */
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001131
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001132 /* allocates framebuffer driver structure, not framebuffer memory */
1133 info = framebuffer_alloc(0, &usbdev->dev);
1134 if (!info) {
1135 retval = -ENOMEM;
1136 dl_err("framebuffer_alloc failed\n");
1137 goto error;
1138 }
Bernie Thompson59277b62009-11-24 15:52:21 -08001139 dev->info = info;
1140 info->par = dev;
1141 info->pseudo_palette = dev->pseudo_palette;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001142 info->fbops = &dlfb_ops;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001143
Bernie Thompson59277b62009-11-24 15:52:21 -08001144 var = &info->var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001145
1146 /* TODO set limit based on actual SKU detection */
1147 dev->sku_pixel_limit = 2048 * 1152;
1148
1149 INIT_LIST_HEAD(&info->modelist);
1150 dlfb_parse_edid(dev, var, info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001151
Bernie Thompson59277b62009-11-24 15:52:21 -08001152 /*
1153 * ok, now that we've got the size info, we can alloc our framebuffer.
Bernie Thompson59277b62009-11-24 15:52:21 -08001154 */
Bernie Thompson59277b62009-11-24 15:52:21 -08001155 info->fix = dlfb_fix;
1156 info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
1157 videomemorysize = info->fix.line_length * var->yres;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001158
Bernie Thompson59277b62009-11-24 15:52:21 -08001159 /*
1160 * The big chunk of system memory we use as a virtual framebuffer.
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001161 * TODO: Handle fbcon cursor code calling blit in interrupt context
Bernie Thompson59277b62009-11-24 15:52:21 -08001162 */
1163 videomemory = vmalloc(videomemorysize);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001164 if (!videomemory) {
1165 retval = -ENOMEM;
1166 dl_err("Virtual framebuffer alloc failed\n");
1167 goto error;
1168 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001169
Bernie Thompson59277b62009-11-24 15:52:21 -08001170 info->screen_base = videomemory;
1171 info->fix.smem_len = PAGE_ALIGN(videomemorysize);
1172 info->fix.smem_start = (unsigned long) videomemory;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001173 info->flags = udlfb_info_flags;
1174
Bernie Thompson59277b62009-11-24 15:52:21 -08001175
1176 /*
1177 * Second framebuffer copy, mirroring the state of the framebuffer
1178 * on the physical USB device. We can function without this.
1179 * But with imperfect damage info we may end up sending pixels over USB
1180 * that were, in fact, unchanged -- wasting limited USB bandwidth
1181 */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001182 dev->backing_buffer = vmalloc(videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001183 if (!dev->backing_buffer)
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001184 dl_warn("No shadow/backing buffer allcoated\n");
1185 else
1186 memset(dev->backing_buffer, 0, videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001187
1188 retval = fb_alloc_cmap(&info->cmap, 256, 0);
1189 if (retval < 0) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001190 dl_err("fb_alloc_cmap failed %x\n", retval);
1191 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001192 }
1193
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001194 /* ready to begin using device */
1195
1196/*
1197#ifdef CONFIG_FB_DEFERRED_IO
1198 atomic_set(&dev->use_defio, 1);
1199#endif
1200*/
1201 atomic_set(&dev->usb_active, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -08001202 dlfb_select_std_channel(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001203
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001204 dlfb_ops_check_var(var, info);
1205 dlfb_ops_set_par(info);
1206
1207 /* paint greenscreen */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001208 pix_framebuffer = (u16 *) videomemory;
1209 for (i = 0; i < videomemorysize / 2; i++)
1210 pix_framebuffer[i] = 0x37e6;
1211
1212 dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
1213 videomemory);
Bernie Thompson530f43a2010-02-15 06:46:21 -08001214
Bernie Thompson59277b62009-11-24 15:52:21 -08001215 retval = register_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001216 if (retval < 0) {
1217 dl_err("register_framebuffer failed %d\n", retval);
1218 goto error;
1219 }
1220 registered = 1;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001221
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001222 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1223 device_create_file(info->dev, &fb_device_attrs[i]);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -07001224
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001225 device_create_bin_file(info->dev, &edid_attr);
1226
1227 dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
1228 " Using %dK framebuffer memory\n", info->node,
1229 var->xres, var->yres,
1230 ((dev->backing_buffer) ?
1231 videomemorysize * 2 : videomemorysize) >> 10);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001232 return 0;
1233
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001234error:
1235 if (dev) {
1236 if (registered) {
1237 unregister_framebuffer(info);
1238 dlfb_ops_destroy(info);
1239 } else
1240 kref_put(&dev->kref, dlfb_delete);
1241
1242 if (dev->urbs.count > 0)
1243 dlfb_free_urb_list(dev);
1244 kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
1245
1246 /* dev has been deallocated. Do not dereference */
1247 }
1248
Bernie Thompson59277b62009-11-24 15:52:21 -08001249 return retval;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001250}
1251
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001252static void dlfb_usb_disconnect(struct usb_interface *interface)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001253{
Bernie Thompson59277b62009-11-24 15:52:21 -08001254 struct dlfb_data *dev;
1255 struct fb_info *info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001256 int i;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001257
Bernie Thompson59277b62009-11-24 15:52:21 -08001258 dev = usb_get_intfdata(interface);
Bernie Thompson59277b62009-11-24 15:52:21 -08001259 info = dev->info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001260
1261 /* when non-active we'll update virtual framebuffer, but no new urbs */
1262 atomic_set(&dev->usb_active, 0);
1263
1264 usb_set_intfdata(interface, NULL);
1265
1266 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1267 device_remove_file(info->dev, &fb_device_attrs[i]);
1268
1269 device_remove_bin_file(info->dev, &edid_attr);
1270
1271 /* this function will wait for all in-flight urbs to complete */
1272 dlfb_free_urb_list(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001273
Bernie Thompson59277b62009-11-24 15:52:21 -08001274 if (info) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001275 dl_notice("Detaching /dev/fb%d\n", info->node);
Bernie Thompson59277b62009-11-24 15:52:21 -08001276 unregister_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001277 dlfb_ops_destroy(info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001278 }
1279
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001280 /* release reference taken by kref_init in probe() */
1281 kref_put(&dev->kref, dlfb_delete);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001282
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001283 /* consider dlfb_data freed */
1284
1285 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001286}
1287
1288static struct usb_driver dlfb_driver = {
1289 .name = "udlfb",
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001290 .probe = dlfb_usb_probe,
1291 .disconnect = dlfb_usb_disconnect,
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001292 .id_table = id_table,
1293};
1294
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001295static int __init dlfb_module_init(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001296{
1297 int res;
1298
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001299 res = usb_register(&dlfb_driver);
1300 if (res)
1301 err("usb_register failed. Error number %d", res);
1302
1303 printk("VMODES initialized\n");
1304
1305 return res;
1306}
1307
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001308static void __exit dlfb_module_exit(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001309{
1310 usb_deregister(&dlfb_driver);
1311}
1312
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001313module_init(dlfb_module_init);
1314module_exit(dlfb_module_exit);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001315
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001316static void dlfb_urb_completion(struct urb *urb)
1317{
1318 struct urb_node *unode = urb->context;
1319 struct dlfb_data *dev = unode->dev;
1320 unsigned long flags;
1321
1322 /* sync/async unlink faults aren't errors */
1323 if (urb->status) {
1324 if (!(urb->status == -ENOENT ||
1325 urb->status == -ECONNRESET ||
1326 urb->status == -ESHUTDOWN)) {
1327 dl_err("%s - nonzero write bulk status received: %d\n",
1328 __func__, urb->status);
1329 atomic_set(&dev->lost_pixels, 1);
1330 }
1331 }
1332
1333 urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
1334
1335 spin_lock_irqsave(&dev->urbs.lock, flags);
1336 list_add_tail(&unode->entry, &dev->urbs.list);
1337 dev->urbs.available++;
1338 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1339
1340 up(&dev->urbs.limit_sem);
1341}
1342
1343static void dlfb_free_urb_list(struct dlfb_data *dev)
1344{
1345 int count = dev->urbs.count;
1346 struct list_head *node;
1347 struct urb_node *unode;
1348 struct urb *urb;
1349 int ret;
1350 unsigned long flags;
1351
1352 dl_notice("Waiting for completes and freeing all render urbs\n");
1353
1354 /* keep waiting and freeing, until we've got 'em all */
1355 while (count--) {
1356 /* Timeout means a memory leak and/or fault */
1357 ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
1358 if (ret) {
1359 BUG_ON(ret);
1360 break;
1361 }
1362 spin_lock_irqsave(&dev->urbs.lock, flags);
1363
1364 node = dev->urbs.list.next; /* have reserved one with sem */
1365 list_del_init(node);
1366
1367 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1368
1369 unode = list_entry(node, struct urb_node, entry);
1370 urb = unode->urb;
1371
1372 /* Free each separately allocated piece */
1373 usb_buffer_free(urb->dev, dev->urbs.size,
1374 urb->transfer_buffer, urb->transfer_dma);
1375 usb_free_urb(urb);
1376 kfree(node);
1377 }
1378
1379 kref_put(&dev->kref, dlfb_delete);
1380
1381}
1382
1383static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
1384{
1385 int i = 0;
1386 struct urb *urb;
1387 struct urb_node *unode;
1388 char *buf;
1389
1390 spin_lock_init(&dev->urbs.lock);
1391
1392 dev->urbs.size = size;
1393 INIT_LIST_HEAD(&dev->urbs.list);
1394
1395 while (i < count) {
1396 unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
1397 if (!unode)
1398 break;
1399 unode->dev = dev;
1400
1401 urb = usb_alloc_urb(0, GFP_KERNEL);
1402 if (!urb) {
1403 kfree(unode);
1404 break;
1405 }
1406 unode->urb = urb;
1407
1408 buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
1409 &urb->transfer_dma);
1410 if (!buf) {
1411 kfree(unode);
1412 usb_free_urb(urb);
1413 break;
1414 }
1415
1416 /* urb->transfer_buffer_length set to actual before submit */
1417 usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
1418 buf, size, dlfb_urb_completion, unode);
1419 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1420
1421 list_add_tail(&unode->entry, &dev->urbs.list);
1422
1423 i++;
1424 }
1425
1426 sema_init(&dev->urbs.limit_sem, i);
1427 dev->urbs.count = i;
1428 dev->urbs.available = i;
1429
1430 kref_get(&dev->kref); /* released in free_render_urbs() */
1431
1432 dl_notice("allocated %d %d byte urbs \n", i, (int) size);
1433
1434 return i;
1435}
1436
1437static struct urb *dlfb_get_urb(struct dlfb_data *dev)
1438{
1439 int ret = 0;
1440 struct list_head *entry;
1441 struct urb_node *unode;
1442 struct urb *urb = NULL;
1443 unsigned long flags;
1444
1445 /* Wait for an in-flight buffer to complete and get re-queued */
1446 ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
1447 if (ret) {
1448 atomic_set(&dev->lost_pixels, 1);
1449 dl_err("wait for urb interrupted: %x\n", ret);
1450 goto error;
1451 }
1452
1453 spin_lock_irqsave(&dev->urbs.lock, flags);
1454
1455 BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
1456 entry = dev->urbs.list.next;
1457 list_del_init(entry);
1458 dev->urbs.available--;
1459
1460 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1461
1462 unode = list_entry(entry, struct urb_node, entry);
1463 urb = unode->urb;
1464
1465error:
1466 return urb;
1467}
1468
1469static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
1470{
1471 int ret;
1472
1473 BUG_ON(len > dev->urbs.size);
1474
1475 urb->transfer_buffer_length = len; /* set to actual payload len */
1476 ret = usb_submit_urb(urb, GFP_KERNEL);
1477 if (ret) {
1478 dlfb_urb_completion(urb); /* because no one else will */
1479 atomic_set(&dev->lost_pixels, 1);
1480 dl_err("usb_submit_urb error %x\n", ret);
1481 }
1482 return ret;
1483}
1484
Bernie Thompson59277b62009-11-24 15:52:21 -08001485MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001486 "Jaya Kumar <jayakumar.lkml@gmail.com>, "
1487 "Bernie Thompson <bernie@plugable.com>");
1488MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001489MODULE_LICENSE("GPL");
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001490