blob: 8ee55c86cff7699bf915acbb90ae065933daf2b5 [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>
26#include <linux/mutex.h>
Amit Kucheriafb299002009-07-27 12:01:03 +030027#include <linux/vmalloc.h>
Roberto De Ioris88e58b12009-06-03 14:03:06 -070028
29#include "udlfb.h"
30
Bernie Thompson59277b62009-11-24 15:52:21 -080031static struct fb_fix_screeninfo dlfb_fix = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -080032 .id = "udlfb",
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080033 .type = FB_TYPE_PACKED_PIXELS,
34 .visual = FB_VISUAL_TRUECOLOR,
35 .xpanstep = 0,
36 .ypanstep = 0,
37 .ywrapstep = 0,
38 .accel = FB_ACCEL_NONE,
Bernie Thompson59277b62009-11-24 15:52:21 -080039};
Roberto De Ioris88e58b12009-06-03 14:03:06 -070040
Bernie Thompson2469d5d2010-02-15 06:46:13 -080041static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
42#ifdef FBINFO_VIRTFB
43 FBINFO_VIRTFB |
44#endif
45 FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT |
46 FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
47
Bernie Thompsoncc403dc2010-02-15 06:45:49 -080048/*
49 * There are many DisplayLink-based products, all with unique PIDs. We are able
50 * to support all volume ones (circa 2009) with a single driver, so we match
51 * globally on VID. TODO: Probe() needs to detect when we might be running
52 * "future" chips, and bail on those, so a compatible driver can match.
53 */
54static struct usb_device_id id_table[] = {
55 {.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
56 {},
57};
58MODULE_DEVICE_TABLE(usb, id_table);
Bernie Thompson59277b62009-11-24 15:52:21 -080059
Bernie Thompson4a4854d2010-02-15 06:45:55 -080060/* dlfb keeps a list of urbs for efficient bulk transfers */
61static void dlfb_urb_completion(struct urb *urb);
62static struct urb *dlfb_get_urb(struct dlfb_data *dev);
63static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
64static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
65static void dlfb_free_urb_list(struct dlfb_data *dev);
66
Bernie Thompson59277b62009-11-24 15:52:21 -080067/*
68 * Inserts a specific DisplayLink controller command into the provided
69 * buffer.
70 */
Bernie Thompson45742032010-02-15 06:46:04 -080071static char *dlfb_set_register(char *buf, u8 reg, u8 val)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070072{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -080073 *buf++ = 0xAF;
74 *buf++ = 0x20;
75 *buf++ = reg;
76 *buf++ = val;
77 return buf;
Roberto De Ioris88e58b12009-06-03 14:03:06 -070078}
79
Bernie Thompson45742032010-02-15 06:46:04 -080080static char *dlfb_vidreg_lock(char *buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -070081{
Bernie Thompson45742032010-02-15 06:46:04 -080082 return dlfb_set_register(buf, 0xFF, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -080083}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070084
Bernie Thompson45742032010-02-15 06:46:04 -080085static char *dlfb_vidreg_unlock(char *buf)
Bernie Thompson59277b62009-11-24 15:52:21 -080086{
Bernie Thompson45742032010-02-15 06:46:04 -080087 return dlfb_set_register(buf, 0xFF, 0xFF);
Bernie Thompson59277b62009-11-24 15:52:21 -080088}
Roberto De Ioris88e58b12009-06-03 14:03:06 -070089
Bernie Thompson59277b62009-11-24 15:52:21 -080090/*
91 * Once you send this command, the DisplayLink framebuffer gets driven to the
92 * display.
93 */
Bernie Thompson45742032010-02-15 06:46:04 -080094static char *dlfb_enable_hvsync(char *buf)
Bernie Thompson59277b62009-11-24 15:52:21 -080095{
Bernie Thompson45742032010-02-15 06:46:04 -080096 return dlfb_set_register(buf, 0x1F, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -080097}
98
Bernie Thompson45742032010-02-15 06:46:04 -080099static char *dlfb_set_color_depth(char *buf, u8 selection)
Bernie Thompson59277b62009-11-24 15:52:21 -0800100{
Bernie Thompson45742032010-02-15 06:46:04 -0800101 return dlfb_set_register(buf, 0x00, selection);
Bernie Thompson59277b62009-11-24 15:52:21 -0800102}
103
Bernie Thompson45742032010-02-15 06:46:04 -0800104static char *dlfb_set_base16bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800105{
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800106 /* the base pointer is 16 bits wide, 0x20 is hi byte. */
Bernie Thompson45742032010-02-15 06:46:04 -0800107 wrptr = dlfb_set_register(wrptr, 0x20, base >> 16);
108 wrptr = dlfb_set_register(wrptr, 0x21, base >> 8);
109 return dlfb_set_register(wrptr, 0x22, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800110}
111
Bernie Thompson45742032010-02-15 06:46:04 -0800112static char *dlfb_set_base8bpp(char *wrptr, u32 base)
Bernie Thompson59277b62009-11-24 15:52:21 -0800113{
Bernie Thompson45742032010-02-15 06:46:04 -0800114 wrptr = dlfb_set_register(wrptr, 0x26, base >> 16);
115 wrptr = dlfb_set_register(wrptr, 0x27, base >> 8);
116 return dlfb_set_register(wrptr, 0x28, base);
Bernie Thompson59277b62009-11-24 15:52:21 -0800117}
118
Bernie Thompson45742032010-02-15 06:46:04 -0800119static char *dlfb_set_register_16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800120{
Bernie Thompson45742032010-02-15 06:46:04 -0800121 wrptr = dlfb_set_register(wrptr, reg, value >> 8);
122 return dlfb_set_register(wrptr, reg+1, value);
Bernie Thompson59277b62009-11-24 15:52:21 -0800123}
124
125/*
126 * This is kind of weird because the controller takes some
127 * register values in a different byte order than other registers.
128 */
Bernie Thompson45742032010-02-15 06:46:04 -0800129static char *dlfb_set_register_16be(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800130{
Bernie Thompson45742032010-02-15 06:46:04 -0800131 wrptr = dlfb_set_register(wrptr, reg, value);
132 return dlfb_set_register(wrptr, reg+1, value >> 8);
Bernie Thompson59277b62009-11-24 15:52:21 -0800133}
134
135/*
136 * LFSR is linear feedback shift register. The reason we have this is
137 * because the display controller needs to minimize the clock depth of
138 * various counters used in the display path. So this code reverses the
139 * provided value into the lfsr16 value by counting backwards to get
140 * the value that needs to be set in the hardware comparator to get the
141 * same actual count. This makes sense once you read above a couple of
142 * times and think about it from a hardware perspective.
143 */
144static u16 lfsr16(u16 actual_count)
145{
146 u32 lv = 0xFFFF; /* This is the lfsr value that the hw starts with */
147
148 while (actual_count--) {
149 lv = ((lv << 1) |
150 (((lv >> 15) ^ (lv >> 4) ^ (lv >> 2) ^ (lv >> 1)) & 1))
151 & 0xFFFF;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700152 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800153
154 return (u16) lv;
155}
156
157/*
158 * This does LFSR conversion on the value that is to be written.
159 * See LFSR explanation above for more detail.
160 */
Bernie Thompson45742032010-02-15 06:46:04 -0800161static char *dlfb_set_register_lfsr16(char *wrptr, u8 reg, u16 value)
Bernie Thompson59277b62009-11-24 15:52:21 -0800162{
Bernie Thompson45742032010-02-15 06:46:04 -0800163 return dlfb_set_register_16(wrptr, reg, lfsr16(value));
Bernie Thompson59277b62009-11-24 15:52:21 -0800164}
165
166/*
167 * This takes a standard fbdev screeninfo struct and all of its monitor mode
168 * details and converts them into the DisplayLink equivalent register commands.
169 */
Bernie Thompson45742032010-02-15 06:46:04 -0800170static char *dlfb_set_vid_cmds(char *wrptr, struct fb_var_screeninfo *var)
Bernie Thompson59277b62009-11-24 15:52:21 -0800171{
172 u16 xds, yds;
173 u16 xde, yde;
174 u16 yec;
175
Bernie Thompson59277b62009-11-24 15:52:21 -0800176 /* x display start */
177 xds = var->left_margin + var->hsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800178 wrptr = dlfb_set_register_lfsr16(wrptr, 0x01, xds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800179 /* x display end */
180 xde = xds + var->xres;
Bernie Thompson45742032010-02-15 06:46:04 -0800181 wrptr = dlfb_set_register_lfsr16(wrptr, 0x03, xde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800182
183 /* y display start */
184 yds = var->upper_margin + var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800185 wrptr = dlfb_set_register_lfsr16(wrptr, 0x05, yds);
Bernie Thompson59277b62009-11-24 15:52:21 -0800186 /* y display end */
187 yde = yds + var->yres;
Bernie Thompson45742032010-02-15 06:46:04 -0800188 wrptr = dlfb_set_register_lfsr16(wrptr, 0x07, yde);
Bernie Thompson59277b62009-11-24 15:52:21 -0800189
190 /* x end count is active + blanking - 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800191 wrptr = dlfb_set_register_lfsr16(wrptr, 0x09,
192 xde + var->right_margin - 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800193
194 /* libdlo hardcodes hsync start to 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800195 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0B, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800196
197 /* hsync end is width of sync pulse + 1 */
Bernie Thompson45742032010-02-15 06:46:04 -0800198 wrptr = dlfb_set_register_lfsr16(wrptr, 0x0D, var->hsync_len + 1);
Bernie Thompson59277b62009-11-24 15:52:21 -0800199
200 /* hpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800201 wrptr = dlfb_set_register_16(wrptr, 0x0F, var->xres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800202
203 /* yendcount is vertical active + vertical blanking */
204 yec = var->yres + var->upper_margin + var->lower_margin +
205 var->vsync_len;
Bernie Thompson45742032010-02-15 06:46:04 -0800206 wrptr = dlfb_set_register_lfsr16(wrptr, 0x11, yec);
Bernie Thompson59277b62009-11-24 15:52:21 -0800207
208 /* libdlo hardcodes vsync start to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800209 wrptr = dlfb_set_register_lfsr16(wrptr, 0x13, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800210
211 /* vsync end is width of vsync pulse */
Bernie Thompson45742032010-02-15 06:46:04 -0800212 wrptr = dlfb_set_register_lfsr16(wrptr, 0x15, var->vsync_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800213
214 /* vpixels is active pixels */
Bernie Thompson45742032010-02-15 06:46:04 -0800215 wrptr = dlfb_set_register_16(wrptr, 0x17, var->yres);
Bernie Thompson59277b62009-11-24 15:52:21 -0800216
217 /* convert picoseconds to 5kHz multiple for pclk5k = x * 1E12/5k */
Bernie Thompson45742032010-02-15 06:46:04 -0800218 wrptr = dlfb_set_register_16be(wrptr, 0x1B,
219 200*1000*1000/var->pixclock);
Bernie Thompson59277b62009-11-24 15:52:21 -0800220
221 return wrptr;
222}
223
224/*
225 * This takes a standard fbdev screeninfo struct that was fetched or prepared
226 * and then generates the appropriate command sequence that then drives the
227 * display controller.
228 */
229static int dlfb_set_video_mode(struct dlfb_data *dev,
230 struct fb_var_screeninfo *var)
231{
232 char *buf;
233 char *wrptr;
234 int retval = 0;
235 int writesize;
236
237 buf = dev->buf;
238
239 /*
240 * This first section has to do with setting the base address on the
241 * controller * associated with the display. There are 2 base
242 * pointers, currently, we only * use the 16 bpp segment.
243 */
Bernie Thompson45742032010-02-15 06:46:04 -0800244 wrptr = dlfb_vidreg_lock(buf);
245 wrptr = dlfb_set_color_depth(wrptr, 0x00);
Bernie Thompson59277b62009-11-24 15:52:21 -0800246 /* set base for 16bpp segment to 0 */
Bernie Thompson45742032010-02-15 06:46:04 -0800247 wrptr = dlfb_set_base16bpp(wrptr, 0);
Bernie Thompson59277b62009-11-24 15:52:21 -0800248 /* set base for 8bpp segment to end of fb */
Bernie Thompson45742032010-02-15 06:46:04 -0800249 wrptr = dlfb_set_base8bpp(wrptr, dev->info->fix.smem_len);
Bernie Thompson59277b62009-11-24 15:52:21 -0800250
Bernie Thompson45742032010-02-15 06:46:04 -0800251 wrptr = dlfb_set_vid_cmds(wrptr, var);
252 wrptr = dlfb_enable_hvsync(wrptr);
253 wrptr = dlfb_vidreg_unlock(wrptr);
Bernie Thompson59277b62009-11-24 15:52:21 -0800254
255 writesize = wrptr - buf;
256
257 mutex_lock(&dev->bulk_mutex);
258 if (!dev->interface) { /* disconnect() was called */
259 mutex_unlock(&dev->bulk_mutex);
260 retval = -ENODEV;
261 goto error;
262 }
263
264 retval = dlfb_bulk_msg(dev, writesize);
265 mutex_unlock(&dev->bulk_mutex);
266 if (retval) {
267 dev_err(&dev->udev->dev, "Problem %d with submit write bulk.\n",
268 retval);
269 goto error;
270 }
271
272 return 0;
273
274error:
275 return retval;
276}
277
Bernie Thompson59277b62009-11-24 15:52:21 -0800278
279/*
280 * Query EDID from the handware, then hand it off to fbdev's edid parse
281 * routine which should give us back a filled in screeninfo structure.
282 */
283static int dlfb_get_var_from_edid(struct dlfb_data *dev,
284 struct fb_var_screeninfo *var)
285{
286 int ret;
287
288 dlfb_edid(dev);
289 ret = fb_parse_edid(dev->edid, var);
290
291 return ret;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700292}
293
Bernie Thompson45742032010-02-15 06:46:04 -0800294static int dlfb_ops_mmap(struct fb_info *info, struct vm_area_struct *vma)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700295{
296 unsigned long start = vma->vm_start;
297 unsigned long size = vma->vm_end - vma->vm_start;
298 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
299 unsigned long page, pos;
300
301 printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
302
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700303 if (offset + size > info->fix.smem_len)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700304 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700305
306 pos = (unsigned long)info->fix.smem_start + offset;
307
308 while (size > 0) {
309 page = vmalloc_to_pfn((void *)pos);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700310 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700311 return -EAGAIN;
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700312
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700313 start += PAGE_SIZE;
314 pos += PAGE_SIZE;
315 if (size > PAGE_SIZE)
316 size -= PAGE_SIZE;
317 else
318 size = 0;
319 }
320
321 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
322 return 0;
323
324}
325
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700326/* ioctl structure */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700327struct dloarea {
328 int x, y;
329 int w, h;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700330 int x2, y2;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700331};
332
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700333static struct usb_driver dlfb_driver;
334
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800335/* thanks to Henrik Bjerregaard Pedersen for this function */
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700336static char *rle_compress16(uint16_t * src, char *dst, int rem)
337{
338
339 int rl;
340 uint16_t pix0;
341 char *end_if_raw = dst + 6 + 2 * rem;
342
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800343 dst += 6; /* header will be filled in if RLE is worth it */
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700344
345 while (rem && dst < end_if_raw) {
346 char *start = (char *)src;
347
348 pix0 = *src++;
349 rl = 1;
350 rem--;
351 while (rem && *src == pix0)
352 rem--, rl++, src++;
353 *dst++ = rl;
354 *dst++ = start[1];
355 *dst++ = start[0];
356 }
357
358 return dst;
359}
360
361/*
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800362Thanks to Henrik Bjerregaard Pedersen for rle implementation
363and code refactoring. Next step is huffman compression.
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700364*/
365
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700366static int
367image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
368 char *data)
369{
370
371 int i, j, base;
372 int rem = width;
373 int ret;
374
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700375 int firstdiff, thistime;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700376
377 char *bufptr;
378
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700379 if (x + width > dev_info->info->var.xres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700380 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700381
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700382 if (y + height > dev_info->info->var.yres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700383 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700384
385 mutex_lock(&dev_info->bulk_mutex);
386
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700387 base =
388 dev_info->base16 + ((dev_info->info->var.xres * 2 * y) + (x * 2));
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700389
390 data += (dev_info->info->var.xres * 2 * y) + (x * 2);
391
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700392 /* printk("IMAGE_BLIT\n"); */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700393
394 bufptr = dev_info->buf;
395
396 for (i = y; i < y + height; i++) {
397
398 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
399 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
400 bufptr = dev_info->buf;
401 }
402
403 rem = width;
404
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700405 /* printk("WRITING LINE %d\n", i); */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700406
407 while (rem) {
408
409 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
410 ret =
411 dlfb_bulk_msg(dev_info,
412 bufptr - dev_info->buf);
413 bufptr = dev_info->buf;
414 }
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800415 /* number of pixels to consider this time */
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700416 thistime = rem;
417 if (thistime > 255)
418 thistime = 255;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700419
Bernie Thompson59277b62009-11-24 15:52:21 -0800420 if (dev_info->backing_buffer) {
421 /* find first pixel that has changed */
422 firstdiff = -1;
423 for (j = 0; j < thistime * 2; j++) {
424 if (dev_info->backing_buffer
425 [base - dev_info->base16 + j]
426 != data[j]) {
427 firstdiff = j / 2;
428 break;
429 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700430 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800431
432 } else {
433 firstdiff = 0;
434
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700435 }
436
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700437 if (firstdiff >= 0) {
438 char *end_of_rle;
439
440 end_of_rle =
441 rle_compress16((uint16_t *) (data +
442 firstdiff * 2),
443 bufptr,
444 thistime - firstdiff);
445
446 if (end_of_rle <
447 bufptr + 6 + 2 * (thistime - firstdiff)) {
448 bufptr[0] = 0xAF;
449 bufptr[1] = 0x69;
450
451 bufptr[2] =
452 (char)((base +
453 firstdiff * 2) >> 16);
454 bufptr[3] =
455 (char)((base + firstdiff * 2) >> 8);
456 bufptr[4] =
457 (char)(base + firstdiff * 2);
458 bufptr[5] = thistime - firstdiff;
459
460 bufptr = end_of_rle;
461
462 } else {
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800463 /* fallback to raw (or other?) */
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700464 *bufptr++ = 0xAF;
465 *bufptr++ = 0x68;
466
467 *bufptr++ =
468 (char)((base +
469 firstdiff * 2) >> 16);
470 *bufptr++ =
471 (char)((base + firstdiff * 2) >> 8);
472 *bufptr++ =
473 (char)(base + firstdiff * 2);
474 *bufptr++ = thistime - firstdiff;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700475 for (j = firstdiff * 2;
476 j < thistime * 2; j += 2) {
477 *bufptr++ = data[j + 1];
478 *bufptr++ = data[j];
479 }
480 }
481 }
482
483 base += thistime * 2;
484 data += thistime * 2;
485 rem -= thistime;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700486 }
487
Bernie Thompson59277b62009-11-24 15:52:21 -0800488 if (dev_info->backing_buffer)
489 memcpy(dev_info->backing_buffer +
490 (base - dev_info->base16) -
491 (width * 2), data - (width * 2), width * 2);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700492
493 base += (dev_info->info->var.xres * 2) - (width * 2);
494 data += (dev_info->info->var.xres * 2) - (width * 2);
495
496 }
497
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700498 if (bufptr > dev_info->buf) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700499 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700500 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700501
502 mutex_unlock(&dev_info->bulk_mutex);
503
504 return base;
505
506}
507
508static int
509draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height,
510 unsigned char red, unsigned char green, unsigned char blue)
511{
512
513 int i, j, base;
514 int ret;
515 unsigned short col =
516 (((((red) & 0xF8) | ((green) >> 5)) & 0xFF) << 8) +
517 (((((green) & 0x1C) << 3) | ((blue) >> 3)) & 0xFF);
518 int rem = width;
519
520 char *bufptr;
521
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700522 if (x + width > dev_info->info->var.xres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700523 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700524
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700525 if (y + height > dev_info->info->var.yres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700526 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700527
528 mutex_lock(&dev_info->bulk_mutex);
529
530 base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2);
531
532 bufptr = dev_info->buf;
533
534 for (i = y; i < y + height; i++) {
535
Bernie Thompson59277b62009-11-24 15:52:21 -0800536 if (dev_info->backing_buffer) {
537 for (j = 0; j < width * 2; j += 2) {
538 dev_info->backing_buffer
539 [base - dev_info->base16 + j] =
540 (char)(col >> 8);
541 dev_info->backing_buffer
542 [base - dev_info->base16 + j + 1] =
543 (char)(col);
544 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700545 }
Bernie Thompson59277b62009-11-24 15:52:21 -0800546
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700547 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
548 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
549 bufptr = dev_info->buf;
550 }
551
552 rem = width;
553
554 while (rem) {
555
556 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
557 ret =
558 dlfb_bulk_msg(dev_info,
559 bufptr - dev_info->buf);
560 bufptr = dev_info->buf;
561 }
562
563 *bufptr++ = 0xAF;
564 *bufptr++ = 0x69;
565
566 *bufptr++ = (char)(base >> 16);
567 *bufptr++ = (char)(base >> 8);
568 *bufptr++ = (char)(base);
569
570 if (rem > 255) {
571 *bufptr++ = 255;
572 *bufptr++ = 255;
573 rem -= 255;
574 base += 255 * 2;
575 } else {
576 *bufptr++ = rem;
577 *bufptr++ = rem;
578 base += rem * 2;
579 rem = 0;
580 }
581
582 *bufptr++ = (char)(col >> 8);
583 *bufptr++ = (char)(col);
584
585 }
586
587 base += (dev_info->info->var.xres * 2) - (width * 2);
588
589 }
590
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700591 if (bufptr > dev_info->buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700592 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700593
594 mutex_unlock(&dev_info->bulk_mutex);
595
596 return 1;
597}
598
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700599static void swapfb(struct dlfb_data *dev_info)
600{
601
602 int tmpbase;
603 char *bufptr;
604
605 mutex_lock(&dev_info->bulk_mutex);
606
607 tmpbase = dev_info->base16;
608
609 dev_info->base16 = dev_info->base16d;
610 dev_info->base16d = tmpbase;
611
612 bufptr = dev_info->buf;
613
614 bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
615
Bernie Thompson1d31a9e2010-02-15 06:45:43 -0800616 /* set addresses */
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700617 bufptr =
618 dlfb_set_register(bufptr, 0x20, (char)(dev_info->base16 >> 16));
619 bufptr = dlfb_set_register(bufptr, 0x21, (char)(dev_info->base16 >> 8));
620 bufptr = dlfb_set_register(bufptr, 0x22, (char)(dev_info->base16));
621
622 bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
623
624 dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
625
626 mutex_unlock(&dev_info->bulk_mutex);
627}
628
629static int copyfb(struct dlfb_data *dev_info)
630{
631 int base;
632 int source;
633 int rem;
634 int i, ret;
635
636 char *bufptr;
637
638 base = dev_info->base16d;
639
640 mutex_lock(&dev_info->bulk_mutex);
641
642 source = dev_info->base16;
643
644 bufptr = dev_info->buf;
645
646 for (i = 0; i < dev_info->info->var.yres; i++) {
647
648 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
649 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
650 bufptr = dev_info->buf;
651 }
652
653 rem = dev_info->info->var.xres;
654
655 while (rem) {
656
657 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
658 ret =
659 dlfb_bulk_msg(dev_info,
660 bufptr - dev_info->buf);
661 bufptr = dev_info->buf;
662
663 }
664
665 *bufptr++ = 0xAF;
666 *bufptr++ = 0x6A;
667
668 *bufptr++ = (char)(base >> 16);
669 *bufptr++ = (char)(base >> 8);
670 *bufptr++ = (char)(base);
671
672 if (rem > 255) {
673 *bufptr++ = 255;
674 *bufptr++ = (char)(source >> 16);
675 *bufptr++ = (char)(source >> 8);
676 *bufptr++ = (char)(source);
677
678 rem -= 255;
679 base += 255 * 2;
680 source += 255 * 2;
681
682 } else {
683 *bufptr++ = rem;
684 *bufptr++ = (char)(source >> 16);
685 *bufptr++ = (char)(source >> 8);
686 *bufptr++ = (char)(source);
687
688 base += rem * 2;
689 source += rem * 2;
690 rem = 0;
691 }
692 }
693 }
694
695 if (bufptr > dev_info->buf)
696 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
697
698 mutex_unlock(&dev_info->bulk_mutex);
699
700 return 1;
701
702}
703
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700704static int
705copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy,
706 int width, int height)
707{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700708 int base;
709 int source;
710 int rem;
711 int i, ret;
712
713 char *bufptr;
714
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700715 if (dx + width > dev_info->info->var.xres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700716 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700717
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700718 if (dy + height > dev_info->info->var.yres)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700719 return -EINVAL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700720
721 mutex_lock(&dev_info->bulk_mutex);
722
723 base =
724 dev_info->base16 + (dev_info->info->var.xres * 2 * dy) + (dx * 2);
725 source = (dev_info->info->var.xres * 2 * sy) + (sx * 2);
726
727 bufptr = dev_info->buf;
728
729 for (i = sy; i < sy + height; i++) {
730
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700731 memcpy(dev_info->backing_buffer + base - dev_info->base16,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700732 dev_info->backing_buffer + source, width * 2);
733
734 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
735 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
736 bufptr = dev_info->buf;
737 }
738
739 rem = width;
740
741 while (rem) {
742
743 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
744 ret =
745 dlfb_bulk_msg(dev_info,
746 bufptr - dev_info->buf);
747 bufptr = dev_info->buf;
748 }
749
750 *bufptr++ = 0xAF;
751 *bufptr++ = 0x6A;
752
753 *bufptr++ = (char)(base >> 16);
754 *bufptr++ = (char)(base >> 8);
755 *bufptr++ = (char)(base);
756
757 if (rem > 255) {
758 *bufptr++ = 255;
759 *bufptr++ = (char)(source >> 16);
760 *bufptr++ = (char)(source >> 8);
761 *bufptr++ = (char)(source);
762
763 rem -= 255;
764 base += 255 * 2;
765 source += 255 * 2;
766
767 } else {
768 *bufptr++ = rem;
769 *bufptr++ = (char)(source >> 16);
770 *bufptr++ = (char)(source >> 8);
771 *bufptr++ = (char)(source);
772
773 base += rem * 2;
774 source += rem * 2;
775 rem = 0;
776 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700777 }
778
779 base += (dev_info->info->var.xres * 2) - (width * 2);
780 source += (dev_info->info->var.xres * 2) - (width * 2);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700781 }
782
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700783 if (bufptr > dev_info->buf)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700784 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700785
786 mutex_unlock(&dev_info->bulk_mutex);
787
788 return 1;
789}
790
Bernie Thompson45742032010-02-15 06:46:04 -0800791static void dlfb_ops_copyarea(struct fb_info *info,
792 const struct fb_copyarea *area)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700793{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700794 struct dlfb_data *dev = info->par;
795
796 copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
797 area->height);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700798}
799
Bernie Thompson45742032010-02-15 06:46:04 -0800800static void dlfb_ops_imageblit(struct fb_info *info,
801 const struct fb_image *image)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700802{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700803 int ret;
804 struct dlfb_data *dev = info->par;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700805 cfb_imageblit(info, image);
806 ret =
807 image_blit(dev, image->dx, image->dy, image->width, image->height,
808 info->screen_base);
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700809}
810
Bernie Thompson45742032010-02-15 06:46:04 -0800811static void dlfb_ops_fillrect(struct fb_info *info,
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700812 const struct fb_fillrect *region)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700813{
814
815 unsigned char red, green, blue;
816 struct dlfb_data *dev = info->par;
817
818 memcpy(&red, &region->color, 1);
819 memcpy(&green, &region->color + 1, 1);
820 memcpy(&blue, &region->color + 2, 1);
821 draw_rect(dev, region->dx, region->dy, region->width, region->height,
822 red, green, blue);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700823 /* printk("FILL RECT %d %d !!!\n", region->dx, region->dy); */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700824
825}
826
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800827static void dlfb_get_edid(struct dlfb_data *dev)
828{
829 int i;
830 int ret;
831 char rbuf[2];
832
833 for (i = 0; i < sizeof(dev->edid); i++) {
834 ret = usb_control_msg(dev->udev,
835 usb_rcvctrlpipe(dev->udev, 0), (0x02),
836 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
837 0);
838 dev->edid[i] = rbuf[1];
839 }
840}
841
Bernie Thompson45742032010-02-15 06:46:04 -0800842static int dlfb_ops_ioctl(struct fb_info *info, unsigned int cmd,
843 unsigned long arg)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700844{
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700845 struct dlfb_data *dev_info = info->par;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700846 struct dloarea *area = NULL;
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700847
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700848 if (cmd == 0xAD) {
849 char *edid = (char *)arg;
850 dlfb_edid(dev_info);
851 if (copy_to_user(edid, dev_info->edid, 128)) {
852 return -EFAULT;
853 }
854 return 0;
855 }
856
857 if (cmd == 0xAA || cmd == 0xAB || cmd == 0xAC) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700858
859 area = (struct dloarea *)arg;
860
861 if (area->x < 0)
862 area->x = 0;
863
864 if (area->x > info->var.xres)
865 area->x = info->var.xres;
866
867 if (area->y < 0)
868 area->y = 0;
869
870 if (area->y > info->var.yres)
871 area->y = info->var.yres;
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700872 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700873
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700874 if (cmd == 0xAA) {
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700875 image_blit(dev_info, area->x, area->y, area->w, area->h,
876 info->screen_base);
877 }
Roberto De Ioris7316bc52009-06-10 23:02:19 -0700878 if (cmd == 0xAC) {
879 copyfb(dev_info);
880 image_blit(dev_info, area->x, area->y, area->w, area->h,
881 info->screen_base);
882 swapfb(dev_info);
883 } else if (cmd == 0xAB) {
884
885 if (area->x2 < 0)
886 area->x2 = 0;
887
888 if (area->y2 < 0)
889 area->y2 = 0;
890
891 copyarea(dev_info,
892 area->x2, area->y2, area->x, area->y, area->w,
893 area->h);
894 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700895 return 0;
896}
897
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -0700898/* taken from vesafb */
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700899static int
Bernie Thompson45742032010-02-15 06:46:04 -0800900dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700901 unsigned blue, unsigned transp, struct fb_info *info)
902{
903 int err = 0;
904
905 if (regno >= info->cmap.len)
906 return 1;
907
908 if (regno < 16) {
909 if (info->var.red.offset == 10) {
910 /* 1:5:5:5 */
911 ((u32 *) (info->pseudo_palette))[regno] =
912 ((red & 0xf800) >> 1) |
913 ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
914 } else {
915 /* 0:5:6:5 */
916 ((u32 *) (info->pseudo_palette))[regno] =
917 ((red & 0xf800)) |
918 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
919 }
920 }
921
922 return err;
923}
924
Bernie Thompson45742032010-02-15 06:46:04 -0800925static int dlfb_ops_release(struct fb_info *info, int user)
Roberto De Ioris88e58b12009-06-03 14:03:06 -0700926{
927 struct dlfb_data *dev_info = info->par;
928 image_blit(dev_info, 0, 0, info->var.xres, info->var.yres,
929 info->screen_base);
930 return 0;
931}
932
Bernie Thompson4a4854d2010-02-15 06:45:55 -0800933/*
934 * Called when all client interfaces to start transactions have been disabled,
935 * and all references to our device instance (dlfb_data) are released.
936 * Every transaction must have a reference, so we know are fully spun down
937 */
938static void dlfb_delete(struct kref *kref)
939{
940 struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
941
942 if (dev->backing_buffer)
943 vfree(dev->backing_buffer);
944
945 kfree(dev);
946}
947
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800948/*
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800949 * Called by fbdev as last part of unregister_framebuffer() process
950 * No new clients can open connections. Deallocate everything fb_info.
951 */
952static void dlfb_ops_destroy(struct fb_info *info)
953{
954 struct dlfb_data *dev = info->par;
955
956 if (info->cmap.len != 0)
957 fb_dealloc_cmap(&info->cmap);
958 if (info->monspecs.modedb)
959 fb_destroy_modedb(info->monspecs.modedb);
960 if (info->screen_base)
961 vfree(info->screen_base);
962
963 fb_destroy_modelist(&info->modelist);
964
965 framebuffer_release(info);
966
967 /* ref taken before register_framebuffer() for dlfb_data clients */
968 kref_put(&dev->kref, dlfb_delete);
969}
970
971/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -0800972 * Check whether a video mode is supported by the DisplayLink chip
973 * We start from monitor's modes, so don't need to filter that here
974 */
975static int dlfb_is_valid_mode(struct fb_videomode *mode,
976 struct fb_info *info)
977{
978 struct dlfb_data *dev = info->par;
979
980 if (mode->xres * mode->yres > dev->sku_pixel_limit)
981 return 0;
982
983 return 1;
984}
985
986static void dlfb_var_color_format(struct fb_var_screeninfo *var)
987{
988 const struct fb_bitfield red = { 11, 5, 0 };
989 const struct fb_bitfield green = { 5, 6, 0 };
990 const struct fb_bitfield blue = { 0, 5, 0 };
991
992 var->bits_per_pixel = 16;
993 var->red = red;
994 var->green = green;
995 var->blue = blue;
996}
997
Bernie Thompson2469d5d2010-02-15 06:46:13 -0800998static int dlfb_ops_check_var(struct fb_var_screeninfo *var,
999 struct fb_info *info)
1000{
1001 struct fb_videomode mode;
1002
1003 /* TODO: support dynamically changing framebuffer size */
1004 if ((var->xres * var->yres * 2) > info->fix.smem_len)
1005 return -EINVAL;
1006
1007 /* set device-specific elements of var unrelated to mode */
1008 dlfb_var_color_format(var);
1009
1010 fb_var_to_videomode(&mode, var);
1011
1012 if (!dlfb_is_valid_mode(&mode, info))
1013 return -EINVAL;
1014
1015 return 0;
1016}
1017
1018static int dlfb_ops_set_par(struct fb_info *info)
1019{
1020 struct dlfb_data *dev = info->par;
1021
1022 dl_notice("set_par mode %dx%d\n", info->var.xres, info->var.yres);
1023
1024 return dlfb_set_video_mode(dev, &info->var);
1025}
1026
Bernie Thompson45742032010-02-15 06:46:04 -08001027static int dlfb_ops_blank(int blank_mode, struct fb_info *info)
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -07001028{
Roberto De Ioris7316bc52009-06-10 23:02:19 -07001029 struct dlfb_data *dev_info = info->par;
1030 char *bufptr = dev_info->buf;
1031
1032 bufptr = dlfb_set_register(bufptr, 0xFF, 0x00);
1033 if (blank_mode != FB_BLANK_UNBLANK) {
1034 bufptr = dlfb_set_register(bufptr, 0x1F, 0x01);
1035 } else {
1036 bufptr = dlfb_set_register(bufptr, 0x1F, 0x00);
1037 }
1038 bufptr = dlfb_set_register(bufptr, 0xFF, 0xFF);
1039
1040 dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
1041
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001042 return 0;
1043}
1044
1045static struct fb_ops dlfb_ops = {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001046 .owner = THIS_MODULE,
Bernie Thompson45742032010-02-15 06:46:04 -08001047 .fb_setcolreg = dlfb_ops_setcolreg,
1048 .fb_fillrect = dlfb_ops_fillrect,
1049 .fb_copyarea = dlfb_ops_copyarea,
1050 .fb_imageblit = dlfb_ops_imageblit,
1051 .fb_mmap = dlfb_ops_mmap,
1052 .fb_ioctl = dlfb_ops_ioctl,
1053 .fb_release = dlfb_ops_release,
1054 .fb_blank = dlfb_ops_blank,
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001055 .fb_check_var = dlfb_ops_check_var,
1056 .fb_set_par = dlfb_ops_set_par,
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001057};
1058
Bernie Thompsoncc403dc2010-02-15 06:45:49 -08001059/*
Bernie Thompson7d9485e2010-02-15 06:46:08 -08001060 * Calls dlfb_get_edid() to query the EDID of attached monitor via usb cmds
1061 * Then parses EDID into three places used by various parts of fbdev:
1062 * fb_var_screeninfo contains the timing of the monitor's preferred mode
1063 * fb_info.monspecs is full parsed EDID info, including monspecs.modedb
1064 * fb_info.modelist is a linked list of all monitor & VESA modes which work
1065 *
1066 * If EDID is not readable/valid, then modelist is all VESA modes,
1067 * monspecs is NULL, and fb_var_screeninfo is set to safe VESA mode
1068 * Returns 0 if EDID parses successfully
1069 */
1070static int dlfb_parse_edid(struct dlfb_data *dev,
1071 struct fb_var_screeninfo *var,
1072 struct fb_info *info)
1073{
1074 int i;
1075 const struct fb_videomode *default_vmode = NULL;
1076 int result = 0;
1077
1078 fb_destroy_modelist(&info->modelist);
1079 memset(&info->monspecs, 0, sizeof(info->monspecs));
1080
1081 dlfb_get_edid(dev);
1082 fb_edid_to_monspecs(dev->edid, &info->monspecs);
1083
1084 if (info->monspecs.modedb_len > 0) {
1085
1086 for (i = 0; i < info->monspecs.modedb_len; i++) {
1087 if (dlfb_is_valid_mode(&info->monspecs.modedb[i], info))
1088 fb_add_videomode(&info->monspecs.modedb[i],
1089 &info->modelist);
1090 }
1091
1092 default_vmode = fb_find_best_display(&info->monspecs,
1093 &info->modelist);
1094 } else {
1095 struct fb_videomode fb_vmode = {0};
1096
1097 dl_err("Unable to get valid EDID from device/display\n");
1098 result = 1;
1099
1100 /*
1101 * Add the standard VESA modes to our modelist
1102 * Since we don't have EDID, there may be modes that
1103 * overspec monitor and/or are incorrect aspect ratio, etc.
1104 * But at least the user has a chance to choose
1105 */
1106 for (i = 0; i < VESA_MODEDB_SIZE; i++) {
1107 if (dlfb_is_valid_mode((struct fb_videomode *)
1108 &vesa_modes[i], info))
1109 fb_add_videomode(&vesa_modes[i],
1110 &info->modelist);
1111 }
1112
1113 /*
1114 * default to resolution safe for projectors
1115 * (since they are most common case without EDID)
1116 */
1117 fb_vmode.xres = 800;
1118 fb_vmode.yres = 600;
1119 fb_vmode.refresh = 60;
1120 default_vmode = fb_find_nearest_mode(&fb_vmode,
1121 &info->modelist);
1122 }
1123
1124 fb_videomode_to_var(var, default_vmode);
1125 dlfb_var_color_format(var);
1126
1127 return result;
1128}
1129
1130static ssize_t metrics_bytes_rendered_show(struct device *fbdev,
1131 struct device_attribute *a, char *buf) {
1132 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1133 struct dlfb_data *dev = fb_info->par;
1134 return snprintf(buf, PAGE_SIZE, "%u\n",
1135 atomic_read(&dev->bytes_rendered));
1136}
1137
1138static ssize_t metrics_bytes_identical_show(struct device *fbdev,
1139 struct device_attribute *a, char *buf) {
1140 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1141 struct dlfb_data *dev = fb_info->par;
1142 return snprintf(buf, PAGE_SIZE, "%u\n",
1143 atomic_read(&dev->bytes_identical));
1144}
1145
1146static ssize_t metrics_bytes_sent_show(struct device *fbdev,
1147 struct device_attribute *a, char *buf) {
1148 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1149 struct dlfb_data *dev = fb_info->par;
1150 return snprintf(buf, PAGE_SIZE, "%u\n",
1151 atomic_read(&dev->bytes_sent));
1152}
1153
1154static ssize_t metrics_cpu_kcycles_used_show(struct device *fbdev,
1155 struct device_attribute *a, char *buf) {
1156 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1157 struct dlfb_data *dev = fb_info->par;
1158 return snprintf(buf, PAGE_SIZE, "%u\n",
1159 atomic_read(&dev->cpu_kcycles_used));
1160}
1161
1162static ssize_t metrics_misc_show(struct device *fbdev,
1163 struct device_attribute *a, char *buf) {
1164 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1165 struct dlfb_data *dev = fb_info->par;
1166 return snprintf(buf, PAGE_SIZE,
1167 "Calls to\ndamage: %u\nblit: %u\n"
1168 "defio faults: %u\ncopy: %u\n"
1169 "fill: %u\n\n"
1170 "active framebuffer clients: %d\n"
1171 "urbs available %d(%d)\n"
1172 "Shadow framebuffer in use? %s\n"
1173 "Any lost pixels? %s\n",
1174 atomic_read(&dev->damage_count),
1175 atomic_read(&dev->blit_count),
1176 atomic_read(&dev->defio_fault_count),
1177 atomic_read(&dev->copy_count),
1178 atomic_read(&dev->fill_count),
1179 dev->fb_count,
1180 dev->urbs.available, dev->urbs.limit_sem.count,
1181 (dev->backing_buffer) ? "yes" : "no",
1182 atomic_read(&dev->lost_pixels) ? "yes" : "no");
1183}
1184
1185static ssize_t edid_show(struct kobject *kobj, struct bin_attribute *a,
1186 char *buf, loff_t off, size_t count) {
1187 struct device *fbdev = container_of(kobj, struct device, kobj);
1188 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1189 struct dlfb_data *dev = fb_info->par;
1190 char *edid = &dev->edid[0];
1191 const size_t size = sizeof(dev->edid);
1192
1193 if (dlfb_parse_edid(dev, &fb_info->var, fb_info))
1194 return 0;
1195
1196 if (off >= size)
1197 return 0;
1198
1199 if (off + count > size)
1200 count = size - off;
1201 memcpy(buf, edid + off, count);
1202
1203 return count;
1204}
1205
1206
1207static ssize_t metrics_reset_store(struct device *fbdev,
1208 struct device_attribute *attr,
1209 const char *buf, size_t count)
1210{
1211 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1212 struct dlfb_data *dev = fb_info->par;
1213
1214 atomic_set(&dev->bytes_rendered, 0);
1215 atomic_set(&dev->bytes_identical, 0);
1216 atomic_set(&dev->bytes_sent, 0);
1217 atomic_set(&dev->cpu_kcycles_used, 0);
1218 atomic_set(&dev->blit_count, 0);
1219 atomic_set(&dev->copy_count, 0);
1220 atomic_set(&dev->fill_count, 0);
1221 atomic_set(&dev->defio_fault_count, 0);
1222 atomic_set(&dev->damage_count, 0);
1223
1224 return count;
1225}
1226
1227static ssize_t use_defio_show(struct device *fbdev,
1228 struct device_attribute *a, char *buf) {
1229 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1230 struct dlfb_data *dev = fb_info->par;
1231 return snprintf(buf, PAGE_SIZE, "%d\n",
1232 atomic_read(&dev->use_defio));
1233}
1234
1235static ssize_t use_defio_store(struct device *fbdev,
1236 struct device_attribute *attr,
1237 const char *buf, size_t count)
1238{
1239 struct fb_info *fb_info = dev_get_drvdata(fbdev);
1240 struct dlfb_data *dev = fb_info->par;
1241
1242 if (count > 0) {
1243 if (buf[0] == '0')
1244 atomic_set(&dev->use_defio, 0);
1245 if (buf[0] == '1')
1246 atomic_set(&dev->use_defio, 1);
1247 }
1248 return count;
1249}
1250
1251static struct bin_attribute edid_attr = {
1252 .attr.name = "edid",
1253 .attr.mode = 0444,
1254 .size = 128,
1255 .read = edid_show,
1256};
1257
1258static struct device_attribute fb_device_attrs[] = {
1259 __ATTR_RO(metrics_bytes_rendered),
1260 __ATTR_RO(metrics_bytes_identical),
1261 __ATTR_RO(metrics_bytes_sent),
1262 __ATTR_RO(metrics_cpu_kcycles_used),
1263 __ATTR_RO(metrics_misc),
1264 __ATTR(metrics_reset, S_IWUGO, NULL, metrics_reset_store),
1265 __ATTR_RW(use_defio),
1266};
1267
1268/*
Bernie Thompsoncc403dc2010-02-15 06:45:49 -08001269 * This is necessary before we can communicate with the display controller.
1270 */
1271static int dlfb_select_std_channel(struct dlfb_data *dev)
1272{
1273 int ret;
1274 u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7,
1275 0x1C, 0x88, 0x5E, 0x15,
1276 0x60, 0xFE, 0xC6, 0x97,
1277 0x16, 0x3D, 0x47, 0xF2 };
1278
1279 ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
1280 NR_USB_REQUEST_CHANNEL,
1281 (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0,
1282 set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT);
1283 return ret;
1284}
1285
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001286
1287static int dlfb_usb_probe(struct usb_interface *interface,
Bernie Thompson59277b62009-11-24 15:52:21 -08001288 const struct usb_device_id *id)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001289{
Bernie Thompson59277b62009-11-24 15:52:21 -08001290 struct usb_device *usbdev;
1291 struct dlfb_data *dev;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001292 struct fb_info *info;
Bernie Thompson59277b62009-11-24 15:52:21 -08001293 int videomemorysize;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001294 int i;
Bernie Thompson59277b62009-11-24 15:52:21 -08001295 unsigned char *videomemory;
1296 int retval = -ENOMEM;
1297 struct fb_var_screeninfo *var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001298 int registered = 0;
1299 u16 *pix_framebuffer;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001300
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001301 /* usb initialization */
1302
1303 usbdev = interface_to_usbdev(interface);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001304
Bernie Thompson59277b62009-11-24 15:52:21 -08001305 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1306 if (dev == NULL) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001307 err("dlfb_usb_probe: failed alloc of dev struct\n");
1308 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001309 }
1310
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001311 /* we need to wait for both usb and fbdev to spin down on disconnect */
1312 kref_init(&dev->kref); /* matching kref_put in usb .disconnect fn */
1313 kref_get(&dev->kref); /* matching kref_put in .fb_destroy function*/
1314
Bernie Thompson59277b62009-11-24 15:52:21 -08001315 mutex_init(&dev->bulk_mutex);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001316
Bernie Thompson59277b62009-11-24 15:52:21 -08001317 dev->udev = usbdev;
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001318 dev->gdev = &usbdev->dev; /* our generic struct device * */
Bernie Thompson59277b62009-11-24 15:52:21 -08001319 usb_set_intfdata(interface, dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001320
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001321 if (!dlfb_alloc_urb_list(dev, WRITES_IN_FLIGHT, MAX_TRANSFER)) {
1322 retval = -ENOMEM;
1323 dl_err("dlfb_alloc_urb_list failed\n");
1324 goto error;
1325 }
1326
1327 mutex_init(&dev->fb_open_lock);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001328
Bernie Thompson59277b62009-11-24 15:52:21 -08001329 /*
1330 * TODO: replace single 64K buffer with buffer list
1331 * and async dispatch
1332 */
1333 dev->buf = kmalloc(BUF_SIZE, GFP_KERNEL);
1334 if (dev->buf == NULL) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001335 dl_err("unable to allocate memory for dlfb commands\n");
1336 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001337 }
Bernie Thompson59277b62009-11-24 15:52:21 -08001338 dev->bufend = dev->buf + BUF_SIZE;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001339
Bernie Thompson59277b62009-11-24 15:52:21 -08001340 dev->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
1341 usb_fill_bulk_urb(dev->tx_urb, dev->udev,
1342 usb_sndbulkpipe(dev->udev, 1), dev->buf, 0,
1343 dlfb_bulk_callback, dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001344
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001345 /* We don't register a new USB class. Our client interface is fbdev */
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001346
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001347 /* allocates framebuffer driver structure, not framebuffer memory */
1348 info = framebuffer_alloc(0, &usbdev->dev);
1349 if (!info) {
1350 retval = -ENOMEM;
1351 dl_err("framebuffer_alloc failed\n");
1352 goto error;
1353 }
Bernie Thompson59277b62009-11-24 15:52:21 -08001354 dev->info = info;
1355 info->par = dev;
1356 info->pseudo_palette = dev->pseudo_palette;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001357 info->fbops = &dlfb_ops;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001358
Bernie Thompson59277b62009-11-24 15:52:21 -08001359 var = &info->var;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001360
1361 /* TODO set limit based on actual SKU detection */
1362 dev->sku_pixel_limit = 2048 * 1152;
1363
1364 INIT_LIST_HEAD(&info->modelist);
1365 dlfb_parse_edid(dev, var, info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001366
Bernie Thompson59277b62009-11-24 15:52:21 -08001367 /*
1368 * ok, now that we've got the size info, we can alloc our framebuffer.
Bernie Thompson59277b62009-11-24 15:52:21 -08001369 */
Bernie Thompson59277b62009-11-24 15:52:21 -08001370 info->fix = dlfb_fix;
1371 info->fix.line_length = var->xres * (var->bits_per_pixel / 8);
1372 videomemorysize = info->fix.line_length * var->yres;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001373
Bernie Thompson59277b62009-11-24 15:52:21 -08001374 /*
1375 * The big chunk of system memory we use as a virtual framebuffer.
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001376 * TODO: Handle fbcon cursor code calling blit in interrupt context
Bernie Thompson59277b62009-11-24 15:52:21 -08001377 */
1378 videomemory = vmalloc(videomemorysize);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001379 if (!videomemory) {
1380 retval = -ENOMEM;
1381 dl_err("Virtual framebuffer alloc failed\n");
1382 goto error;
1383 }
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001384
Bernie Thompson59277b62009-11-24 15:52:21 -08001385 info->screen_base = videomemory;
1386 info->fix.smem_len = PAGE_ALIGN(videomemorysize);
1387 info->fix.smem_start = (unsigned long) videomemory;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001388 info->flags = udlfb_info_flags;
1389
Bernie Thompson59277b62009-11-24 15:52:21 -08001390
1391 /*
1392 * Second framebuffer copy, mirroring the state of the framebuffer
1393 * on the physical USB device. We can function without this.
1394 * But with imperfect damage info we may end up sending pixels over USB
1395 * that were, in fact, unchanged -- wasting limited USB bandwidth
1396 */
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001397 dev->backing_buffer = vmalloc(videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001398 if (!dev->backing_buffer)
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001399 dl_warn("No shadow/backing buffer allcoated\n");
1400 else
1401 memset(dev->backing_buffer, 0, videomemorysize);
Bernie Thompson59277b62009-11-24 15:52:21 -08001402
1403 retval = fb_alloc_cmap(&info->cmap, 256, 0);
1404 if (retval < 0) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001405 dl_err("fb_alloc_cmap failed %x\n", retval);
1406 goto error;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001407 }
1408
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001409 /* ready to begin using device */
1410
1411/*
1412#ifdef CONFIG_FB_DEFERRED_IO
1413 atomic_set(&dev->use_defio, 1);
1414#endif
1415*/
1416 atomic_set(&dev->usb_active, 1);
Bernie Thompson59277b62009-11-24 15:52:21 -08001417 dlfb_select_std_channel(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001418
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001419 dlfb_ops_check_var(var, info);
1420 dlfb_ops_set_par(info);
1421
1422 /* paint greenscreen */
1423/*
1424 pix_framebuffer = (u16 *) videomemory;
1425 for (i = 0; i < videomemorysize / 2; i++)
1426 pix_framebuffer[i] = 0x37e6;
1427
1428 dlfb_handle_damage(dev, 0, 0, info->var.xres, info->var.yres,
1429 videomemory);
1430*/
Bernie Thompson59277b62009-11-24 15:52:21 -08001431 retval = register_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001432 if (retval < 0) {
1433 dl_err("register_framebuffer failed %d\n", retval);
1434 goto error;
1435 }
1436 registered = 1;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001437
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001438 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1439 device_create_file(info->dev, &fb_device_attrs[i]);
Greg Kroah-Hartmanf05e0572009-06-03 14:47:08 -07001440
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001441 device_create_bin_file(info->dev, &edid_attr);
1442
1443 dl_err("DisplayLink USB device /dev/fb%d attached. %dx%d resolution."
1444 " Using %dK framebuffer memory\n", info->node,
1445 var->xres, var->yres,
1446 ((dev->backing_buffer) ?
1447 videomemorysize * 2 : videomemorysize) >> 10);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001448 return 0;
1449
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001450error:
1451 if (dev) {
1452 if (registered) {
1453 unregister_framebuffer(info);
1454 dlfb_ops_destroy(info);
1455 } else
1456 kref_put(&dev->kref, dlfb_delete);
1457
1458 if (dev->urbs.count > 0)
1459 dlfb_free_urb_list(dev);
1460 kref_put(&dev->kref, dlfb_delete); /* last ref from kref_init */
1461
1462 /* dev has been deallocated. Do not dereference */
1463 }
1464
Bernie Thompson59277b62009-11-24 15:52:21 -08001465 return retval;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001466}
1467
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001468static void dlfb_usb_disconnect(struct usb_interface *interface)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001469{
Bernie Thompson59277b62009-11-24 15:52:21 -08001470 struct dlfb_data *dev;
1471 struct fb_info *info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001472 int i;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001473
Bernie Thompson59277b62009-11-24 15:52:21 -08001474 dev = usb_get_intfdata(interface);
Bernie Thompson59277b62009-11-24 15:52:21 -08001475 info = dev->info;
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001476
1477 /* when non-active we'll update virtual framebuffer, but no new urbs */
1478 atomic_set(&dev->usb_active, 0);
1479
1480 usb_set_intfdata(interface, NULL);
1481
1482 for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++)
1483 device_remove_file(info->dev, &fb_device_attrs[i]);
1484
1485 device_remove_bin_file(info->dev, &edid_attr);
1486
1487 /* this function will wait for all in-flight urbs to complete */
1488 dlfb_free_urb_list(dev);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001489
Bernie Thompson59277b62009-11-24 15:52:21 -08001490 if (info) {
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001491 dl_notice("Detaching /dev/fb%d\n", info->node);
Bernie Thompson59277b62009-11-24 15:52:21 -08001492 unregister_framebuffer(info);
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001493 dlfb_ops_destroy(info);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001494 }
1495
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001496 /* release reference taken by kref_init in probe() */
1497 kref_put(&dev->kref, dlfb_delete);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001498
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001499 /* consider dlfb_data freed */
1500
1501 return;
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001502}
1503
1504static struct usb_driver dlfb_driver = {
1505 .name = "udlfb",
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001506 .probe = dlfb_usb_probe,
1507 .disconnect = dlfb_usb_disconnect,
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001508 .id_table = id_table,
1509};
1510
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001511static int __init dlfb_module_init(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001512{
1513 int res;
1514
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001515 res = usb_register(&dlfb_driver);
1516 if (res)
1517 err("usb_register failed. Error number %d", res);
1518
1519 printk("VMODES initialized\n");
1520
1521 return res;
1522}
1523
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001524static void __exit dlfb_module_exit(void)
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001525{
1526 usb_deregister(&dlfb_driver);
1527}
1528
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001529module_init(dlfb_module_init);
1530module_exit(dlfb_module_exit);
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001531
Bernie Thompson4a4854d2010-02-15 06:45:55 -08001532static void dlfb_urb_completion(struct urb *urb)
1533{
1534 struct urb_node *unode = urb->context;
1535 struct dlfb_data *dev = unode->dev;
1536 unsigned long flags;
1537
1538 /* sync/async unlink faults aren't errors */
1539 if (urb->status) {
1540 if (!(urb->status == -ENOENT ||
1541 urb->status == -ECONNRESET ||
1542 urb->status == -ESHUTDOWN)) {
1543 dl_err("%s - nonzero write bulk status received: %d\n",
1544 __func__, urb->status);
1545 atomic_set(&dev->lost_pixels, 1);
1546 }
1547 }
1548
1549 urb->transfer_buffer_length = dev->urbs.size; /* reset to actual */
1550
1551 spin_lock_irqsave(&dev->urbs.lock, flags);
1552 list_add_tail(&unode->entry, &dev->urbs.list);
1553 dev->urbs.available++;
1554 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1555
1556 up(&dev->urbs.limit_sem);
1557}
1558
1559static void dlfb_free_urb_list(struct dlfb_data *dev)
1560{
1561 int count = dev->urbs.count;
1562 struct list_head *node;
1563 struct urb_node *unode;
1564 struct urb *urb;
1565 int ret;
1566 unsigned long flags;
1567
1568 dl_notice("Waiting for completes and freeing all render urbs\n");
1569
1570 /* keep waiting and freeing, until we've got 'em all */
1571 while (count--) {
1572 /* Timeout means a memory leak and/or fault */
1573 ret = down_timeout(&dev->urbs.limit_sem, FREE_URB_TIMEOUT);
1574 if (ret) {
1575 BUG_ON(ret);
1576 break;
1577 }
1578 spin_lock_irqsave(&dev->urbs.lock, flags);
1579
1580 node = dev->urbs.list.next; /* have reserved one with sem */
1581 list_del_init(node);
1582
1583 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1584
1585 unode = list_entry(node, struct urb_node, entry);
1586 urb = unode->urb;
1587
1588 /* Free each separately allocated piece */
1589 usb_buffer_free(urb->dev, dev->urbs.size,
1590 urb->transfer_buffer, urb->transfer_dma);
1591 usb_free_urb(urb);
1592 kfree(node);
1593 }
1594
1595 kref_put(&dev->kref, dlfb_delete);
1596
1597}
1598
1599static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size)
1600{
1601 int i = 0;
1602 struct urb *urb;
1603 struct urb_node *unode;
1604 char *buf;
1605
1606 spin_lock_init(&dev->urbs.lock);
1607
1608 dev->urbs.size = size;
1609 INIT_LIST_HEAD(&dev->urbs.list);
1610
1611 while (i < count) {
1612 unode = kzalloc(sizeof(struct urb_node), GFP_KERNEL);
1613 if (!unode)
1614 break;
1615 unode->dev = dev;
1616
1617 urb = usb_alloc_urb(0, GFP_KERNEL);
1618 if (!urb) {
1619 kfree(unode);
1620 break;
1621 }
1622 unode->urb = urb;
1623
1624 buf = usb_buffer_alloc(dev->udev, MAX_TRANSFER, GFP_KERNEL,
1625 &urb->transfer_dma);
1626 if (!buf) {
1627 kfree(unode);
1628 usb_free_urb(urb);
1629 break;
1630 }
1631
1632 /* urb->transfer_buffer_length set to actual before submit */
1633 usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 1),
1634 buf, size, dlfb_urb_completion, unode);
1635 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
1636
1637 list_add_tail(&unode->entry, &dev->urbs.list);
1638
1639 i++;
1640 }
1641
1642 sema_init(&dev->urbs.limit_sem, i);
1643 dev->urbs.count = i;
1644 dev->urbs.available = i;
1645
1646 kref_get(&dev->kref); /* released in free_render_urbs() */
1647
1648 dl_notice("allocated %d %d byte urbs \n", i, (int) size);
1649
1650 return i;
1651}
1652
1653static struct urb *dlfb_get_urb(struct dlfb_data *dev)
1654{
1655 int ret = 0;
1656 struct list_head *entry;
1657 struct urb_node *unode;
1658 struct urb *urb = NULL;
1659 unsigned long flags;
1660
1661 /* Wait for an in-flight buffer to complete and get re-queued */
1662 ret = down_timeout(&dev->urbs.limit_sem, GET_URB_TIMEOUT);
1663 if (ret) {
1664 atomic_set(&dev->lost_pixels, 1);
1665 dl_err("wait for urb interrupted: %x\n", ret);
1666 goto error;
1667 }
1668
1669 spin_lock_irqsave(&dev->urbs.lock, flags);
1670
1671 BUG_ON(list_empty(&dev->urbs.list)); /* reserved one with limit_sem */
1672 entry = dev->urbs.list.next;
1673 list_del_init(entry);
1674 dev->urbs.available--;
1675
1676 spin_unlock_irqrestore(&dev->urbs.lock, flags);
1677
1678 unode = list_entry(entry, struct urb_node, entry);
1679 urb = unode->urb;
1680
1681error:
1682 return urb;
1683}
1684
1685static int dlfb_submit_urb(struct dlfb_data *dev, struct urb *urb, size_t len)
1686{
1687 int ret;
1688
1689 BUG_ON(len > dev->urbs.size);
1690
1691 urb->transfer_buffer_length = len; /* set to actual payload len */
1692 ret = usb_submit_urb(urb, GFP_KERNEL);
1693 if (ret) {
1694 dlfb_urb_completion(urb); /* because no one else will */
1695 atomic_set(&dev->lost_pixels, 1);
1696 dl_err("usb_submit_urb error %x\n", ret);
1697 }
1698 return ret;
1699}
1700
Bernie Thompson59277b62009-11-24 15:52:21 -08001701MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>, "
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001702 "Jaya Kumar <jayakumar.lkml@gmail.com>, "
1703 "Bernie Thompson <bernie@plugable.com>");
1704MODULE_DESCRIPTION("DisplayLink kernel framebuffer driver");
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001705MODULE_LICENSE("GPL");
Bernie Thompson2469d5d2010-02-15 06:46:13 -08001706