blob: 8341b0e904bd0decd8ef6f1455a799de962b98b0 [file] [log] [blame]
Roberto De Ioris88e58b12009-06-03 14:03:06 -07001/*****************************************************************************
2 * DLFB Kernel Driver *
3 * Version 0.2 (udlfb) *
4 * (C) 2009 Roberto De Ioris <roberto@unbit.it> *
5 * *
6 * This file is licensed under the GPLv2. See COPYING in the package. *
7 * Based on the amazing work of Florian Echtler and libdlo 0.1 *
8 * *
9 * *
10 * 31.05.09 release 0.2 *
11 * 22.05.09 First public (ugly) release *
12 *****************************************************************************/
13
14#include <linux/module.h>
15#include <linux/kernel.h>
16#include <linux/init.h>
17#include <linux/usb.h>
18#include <linux/uaccess.h>
19#include <linux/mm.h>
20#include <linux/fb.h>
21#include <linux/mutex.h>
22
23#include "udlfb.h"
24
25#define DRIVER_VERSION "DLFB 0.2"
26
27// memory functions taken from vfb
28
29static void *rvmalloc(unsigned long size)
30{
31 void *mem;
32 unsigned long adr;
33
34 size = PAGE_ALIGN(size);
35 mem = vmalloc_32(size);
36 if (!mem)
37 return NULL;
38
39 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
40 adr = (unsigned long)mem;
41 while (size > 0) {
42 SetPageReserved(vmalloc_to_page((void *)adr));
43 adr += PAGE_SIZE;
44 size -= PAGE_SIZE;
45 }
46
47 return mem;
48}
49
50static void rvfree(void *mem, unsigned long size)
51{
52 unsigned long adr;
53
54 if (!mem)
55 return;
56
57 adr = (unsigned long)mem;
58 while ((long)size > 0) {
59 ClearPageReserved(vmalloc_to_page((void *)adr));
60 adr += PAGE_SIZE;
61 size -= PAGE_SIZE;
62 }
63 vfree(mem);
64}
65
66static int dlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
67{
68 unsigned long start = vma->vm_start;
69 unsigned long size = vma->vm_end - vma->vm_start;
70 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
71 unsigned long page, pos;
72
73 printk("MMAP: %lu %u\n", offset + size, info->fix.smem_len);
74
75 if (offset + size > info->fix.smem_len) {
76 return -EINVAL;
77 }
78
79 pos = (unsigned long)info->fix.smem_start + offset;
80
81 while (size > 0) {
82 page = vmalloc_to_pfn((void *)pos);
83 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
84 return -EAGAIN;
85 }
86 start += PAGE_SIZE;
87 pos += PAGE_SIZE;
88 if (size > PAGE_SIZE)
89 size -= PAGE_SIZE;
90 else
91 size = 0;
92 }
93
94 vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
95 return 0;
96
97}
98
99//
100
101//ioctl structure
102struct dloarea {
103 int x, y;
104 int w, h;
105};
106
107/*
108
109static struct usb_device_id id_table [] = {
110 { USB_DEVICE(0x17e9, 0x023d) },
111 { }
112};
113
114*/
115
116static struct usb_device_id id_table[] = {
117 {.idVendor = 0x17e9,.match_flags = USB_DEVICE_ID_MATCH_VENDOR,},
118 {},
119};
120
121MODULE_DEVICE_TABLE(usb, id_table);
122
123static struct usb_driver dlfb_driver;
124
125static int
126image_blit(struct dlfb_data *dev_info, int x, int y, int width, int height,
127 char *data)
128{
129
130 int i, j, base;
131 int rem = width;
132 int ret;
133
134 int diff;
135
136 char *bufptr;
137
138 if (x + width > dev_info->info->var.xres) {
139 return -EINVAL;
140 }
141
142 if (y + height > dev_info->info->var.yres) {
143 return -EINVAL;
144 }
145
146 mutex_lock(&dev_info->bulk_mutex);
147
148 base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2);
149
150 data += (dev_info->info->var.xres * 2 * y) + (x * 2);
151
152 //printk("IMAGE_BLIT\n");
153
154 bufptr = dev_info->buf;
155
156 for (i = y; i < y + height; i++) {
157
158 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
159 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
160 bufptr = dev_info->buf;
161 }
162
163 rem = width;
164
165 //printk("WRITING LINE %d\n", i);
166
167 while (rem) {
168
169 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
170 ret =
171 dlfb_bulk_msg(dev_info,
172 bufptr - dev_info->buf);
173 bufptr = dev_info->buf;
174 }
175
176 if (rem > 255) {
177
178 diff = 0;
179 for (j = 0; j < 510; j++) {
180 if (dev_info->
181 backing_buffer[base + j] !=
182 data[j]) {
183 diff = 1;
184 break;
185 }
186 }
187
188 if (diff == 1) {
189 *bufptr++ = 0xAF;
190 *bufptr++ = 0x68;
191
192 *bufptr++ = (char)(base >> 16);
193 *bufptr++ = (char)(base >> 8);
194 *bufptr++ = (char)(base);
195 *bufptr++ = 255;
196 // PUT COMPRESSION HERE
197 for (j = 0; j < 510; j += 2) {
198 bufptr[j] = data[j + 1];
199 bufptr[j + 1] = data[j];
200 }
201 bufptr += 510;
202 }
203
204 rem -= 255;
205 base += 510;
206 data += 510;
207 } else {
208
209 diff = 0;
210
211 for (j = 0; j < rem * 2; j++) {
212 if (dev_info->
213 backing_buffer[base + j] !=
214 data[j]) {
215 diff = 1;
216 break;
217 }
218 }
219
220 if (diff == 1) {
221
222 *bufptr++ = 0xAF;
223 *bufptr++ = 0x68;
224
225 *bufptr++ = (char)(base >> 16);
226 *bufptr++ = (char)(base >> 8);
227 *bufptr++ = (char)(base);
228 *bufptr++ = rem;
229 // PUT COMPRESSION HERE
230 for (j = 0; j < rem * 2; j += 2) {
231 bufptr[j] = data[j + 1];
232 bufptr[j + 1] = data[j];
233 }
234 bufptr += rem * 2;
235
236 }
237
238 base += rem * 2;
239 data += rem * 2;
240 rem = 0;
241 }
242
243 }
244
245 memcpy(dev_info->backing_buffer + base - (width * 2),
246 data - (width * 2), width * 2);
247
248 base += (dev_info->info->var.xres * 2) - (width * 2);
249 data += (dev_info->info->var.xres * 2) - (width * 2);
250
251 }
252
253 if (bufptr > dev_info->buf) {
254 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
255 }
256
257 mutex_unlock(&dev_info->bulk_mutex);
258
259 return base;
260
261}
262
263static int
264draw_rect(struct dlfb_data *dev_info, int x, int y, int width, int height,
265 unsigned char red, unsigned char green, unsigned char blue)
266{
267
268 int i, j, base;
269 int ret;
270 unsigned short col =
271 (((((red) & 0xF8) | ((green) >> 5)) & 0xFF) << 8) +
272 (((((green) & 0x1C) << 3) | ((blue) >> 3)) & 0xFF);
273 int rem = width;
274
275 char *bufptr;
276
277 if (x + width > dev_info->info->var.xres) {
278 return -EINVAL;
279 }
280
281 if (y + height > dev_info->info->var.yres) {
282 return -EINVAL;
283 }
284
285 mutex_lock(&dev_info->bulk_mutex);
286
287 base = dev_info->base16 + (dev_info->info->var.xres * 2 * y) + (x * 2);
288
289 bufptr = dev_info->buf;
290
291 for (i = y; i < y + height; i++) {
292
293 for (j = 0; j < width * 2; j += 2) {
294 dev_info->backing_buffer[base + j] = (char)(col >> 8);
295 dev_info->backing_buffer[base + j + 1] = (char)(col);
296 }
297 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
298 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
299 bufptr = dev_info->buf;
300 }
301
302 rem = width;
303
304 while (rem) {
305
306 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
307 ret =
308 dlfb_bulk_msg(dev_info,
309 bufptr - dev_info->buf);
310 bufptr = dev_info->buf;
311 }
312
313 *bufptr++ = 0xAF;
314 *bufptr++ = 0x69;
315
316 *bufptr++ = (char)(base >> 16);
317 *bufptr++ = (char)(base >> 8);
318 *bufptr++ = (char)(base);
319
320 if (rem > 255) {
321 *bufptr++ = 255;
322 *bufptr++ = 255;
323 rem -= 255;
324 base += 255 * 2;
325 } else {
326 *bufptr++ = rem;
327 *bufptr++ = rem;
328 base += rem * 2;
329 rem = 0;
330 }
331
332 *bufptr++ = (char)(col >> 8);
333 *bufptr++ = (char)(col);
334
335 }
336
337 base += (dev_info->info->var.xres * 2) - (width * 2);
338
339 }
340
341 if (bufptr > dev_info->buf) {
342 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
343 }
344
345 mutex_unlock(&dev_info->bulk_mutex);
346
347 return 1;
348}
349
350static int
351copyarea(struct dlfb_data *dev_info, int dx, int dy, int sx, int sy,
352 int width, int height)
353{
354
355 int base;
356 int source;
357 int rem;
358 int i, ret;
359
360 char *bufptr;
361
362 if (dx + width > dev_info->info->var.xres) {
363 return -EINVAL;
364 }
365
366 if (dy + height > dev_info->info->var.yres) {
367 return -EINVAL;
368 }
369
370 mutex_lock(&dev_info->bulk_mutex);
371
372 base =
373 dev_info->base16 + (dev_info->info->var.xres * 2 * dy) + (dx * 2);
374 source = (dev_info->info->var.xres * 2 * sy) + (sx * 2);
375
376 bufptr = dev_info->buf;
377
378 for (i = sy; i < sy + height; i++) {
379
380 memcpy(dev_info->backing_buffer + base,
381 dev_info->backing_buffer + source, width * 2);
382
383 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
384 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
385 bufptr = dev_info->buf;
386 }
387
388 rem = width;
389
390 while (rem) {
391
392 if (dev_info->bufend - bufptr < BUF_HIGH_WATER_MARK) {
393 ret =
394 dlfb_bulk_msg(dev_info,
395 bufptr - dev_info->buf);
396 bufptr = dev_info->buf;
397 }
398
399 *bufptr++ = 0xAF;
400 *bufptr++ = 0x6A;
401
402 *bufptr++ = (char)(base >> 16);
403 *bufptr++ = (char)(base >> 8);
404 *bufptr++ = (char)(base);
405
406 if (rem > 255) {
407 *bufptr++ = 255;
408 *bufptr++ = (char)(source >> 16);
409 *bufptr++ = (char)(source >> 8);
410 *bufptr++ = (char)(source);
411
412 rem -= 255;
413 base += 255 * 2;
414 source += 255 * 2;
415
416 } else {
417 *bufptr++ = rem;
418 *bufptr++ = (char)(source >> 16);
419 *bufptr++ = (char)(source >> 8);
420 *bufptr++ = (char)(source);
421
422 base += rem * 2;
423 source += rem * 2;
424 rem = 0;
425 }
426
427 }
428
429 base += (dev_info->info->var.xres * 2) - (width * 2);
430 source += (dev_info->info->var.xres * 2) - (width * 2);
431
432 }
433
434 if (bufptr > dev_info->buf) {
435 ret = dlfb_bulk_msg(dev_info, bufptr - dev_info->buf);
436 }
437
438 mutex_unlock(&dev_info->bulk_mutex);
439
440 return 1;
441}
442
443void dlfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
444{
445
446 struct dlfb_data *dev = info->par;
447
448 copyarea(dev, area->dx, area->dy, area->sx, area->sy, area->width,
449 area->height);
450
451 //printk("COPY AREA %d %d %d %d %d %d !!!\n", area->dx, area->dy, area->sx, area->sy, area->width, area->height);
452
453}
454
455void dlfb_imageblit(struct fb_info *info, const struct fb_image *image)
456{
457
458 int ret;
459 struct dlfb_data *dev = info->par;
460 //printk("IMAGE BLIT (1) %d %d %d %d DEPTH %d {%p}!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev);
461 cfb_imageblit(info, image);
462 ret =
463 image_blit(dev, image->dx, image->dy, image->width, image->height,
464 info->screen_base);
465 //printk("IMAGE BLIT (2) %d %d %d %d DEPTH %d {%p} %d!!!\n", image->dx, image->dy, image->width, image->height, image->depth, dev->udev, ret);
466}
467
468void dlfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
469{
470
471 unsigned char red, green, blue;
472 struct dlfb_data *dev = info->par;
473
474 memcpy(&red, &region->color, 1);
475 memcpy(&green, &region->color + 1, 1);
476 memcpy(&blue, &region->color + 2, 1);
477 draw_rect(dev, region->dx, region->dy, region->width, region->height,
478 red, green, blue);
479 //printk("FILL RECT %d %d !!!\n", region->dx, region->dy);
480
481}
482
483static int dlfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
484{
485
486 struct dlfb_data *dev_info = info->par;
487 struct dloarea *area;
488
489 if (cmd == 0xAA) {
490
491 area = (struct dloarea *)arg;
492
493 if (area->x < 0)
494 area->x = 0;
495
496 if (area->x > info->var.xres)
497 area->x = info->var.xres;
498
499 if (area->y < 0)
500 area->y = 0;
501
502 if (area->y > info->var.yres)
503 area->y = info->var.yres;
504
505 image_blit(dev_info, area->x, area->y, area->w, area->h,
506 info->screen_base);
507 }
508 return 0;
509}
510
511// taken from vesafb
512
513static int
514dlfb_setcolreg(unsigned regno, unsigned red, unsigned green,
515 unsigned blue, unsigned transp, struct fb_info *info)
516{
517 int err = 0;
518
519 if (regno >= info->cmap.len)
520 return 1;
521
522 if (regno < 16) {
523 if (info->var.red.offset == 10) {
524 /* 1:5:5:5 */
525 ((u32 *) (info->pseudo_palette))[regno] =
526 ((red & 0xf800) >> 1) |
527 ((green & 0xf800) >> 6) | ((blue & 0xf800) >> 11);
528 } else {
529 /* 0:5:6:5 */
530 ((u32 *) (info->pseudo_palette))[regno] =
531 ((red & 0xf800)) |
532 ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
533 }
534 }
535
536 return err;
537}
538
539static int dlfb_release(struct fb_info *info, int user)
540{
541 struct dlfb_data *dev_info = info->par;
542 image_blit(dev_info, 0, 0, info->var.xres, info->var.yres,
543 info->screen_base);
544 return 0;
545}
546
547static int dlfb_blank(int blank_mode, struct fb_info *info) {
548 return 0;
549}
550
551static struct fb_ops dlfb_ops = {
552
553 .fb_setcolreg = dlfb_setcolreg,
554 .fb_fillrect = dlfb_fillrect,
555 .fb_copyarea = dlfb_copyarea,
556 .fb_imageblit = dlfb_imageblit,
557 .fb_mmap = dlfb_mmap,
558 .fb_ioctl = dlfb_ioctl,
559 .fb_release = dlfb_release,
560 .fb_blank = dlfb_blank,
561};
562
563static int
564dlfb_probe(struct usb_interface *interface, const struct usb_device_id *id)
565{
566 struct dlfb_data *dev_info;
567 struct fb_info *info;
568 int i;
569
570 int ret;
571 char rbuf[4];
572
573 dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL);
574 if (dev_info == NULL) {
575 printk("cannot allocate dev_info structure.\n");
576 return -ENOMEM;
577 }
578
579 mutex_init(&dev_info->bulk_mutex);
580
581 dev_info->udev = usb_get_dev(interface_to_usbdev(interface));
582 dev_info->interface = interface;
583
584 printk("DisplayLink device attached\n");
585
586 // add framebuffer info to usb interface
587 usb_set_intfdata(interface, dev_info);
588
589 dev_info->buf = kmalloc(BUF_SIZE, GFP_KERNEL); //usb_buffer_alloc(dev_info->udev, BUF_SIZE , GFP_KERNEL, &dev_info->tx_urb->transfer_dma);
590
591 if (dev_info->buf == NULL) {
592 printk("unable to allocate memory for dlfb commands\n");
593 goto out;
594 }
595 dev_info->bufend = dev_info->buf + BUF_SIZE;
596
597 dev_info->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
598 usb_fill_bulk_urb(dev_info->tx_urb, dev_info->udev,
599 usb_sndbulkpipe(dev_info->udev, 1), dev_info->buf, 0,
600 dlfb_bulk_callback, dev_info);
601
602 ret =
603 usb_control_msg(dev_info->udev, usb_rcvctrlpipe(dev_info->udev, 0),
604 (0x06), (0x80 | (0x02 << 5)), 0, 0, rbuf, 4, 0);
605 printk("ret control msg 0: %d %x%x%x%x\n", ret, rbuf[0], rbuf[1],
606 rbuf[2], rbuf[3]);
607
608 for (i = 0; i < 128; i++) {
609 ret =
610 usb_control_msg(dev_info->udev,
611 usb_rcvctrlpipe(dev_info->udev, 0), (0x02),
612 (0x80 | (0x02 << 5)), i << 8, 0xA1, rbuf, 2,
613 0);
614 //printk("ret control msg edid %d: %d [%d]\n",i, ret, rbuf[1]);
615 dev_info->edid[i] = rbuf[1];
616 }
617
618 info = framebuffer_alloc(sizeof(u32) * 256, &dev_info->udev->dev);
619
620 if (!info) {
621 printk("non posso allocare il framebuffer displaylink");
622 goto out;
623 }
624
625 fb_parse_edid(dev_info->edid, &info->var);
626
627 printk("EDID XRES %d YRES %d\n", info->var.xres, info->var.yres);
628
629 if (dlfb_set_video_mode(dev_info, info->var.xres, info->var.yres) != 0) {
630 goto out;
631 }
632
633 printk("found valid mode...%d\n", info->var.pixclock);
634
635 info->pseudo_palette = info->par;
636 info->par = dev_info;
637
638 dev_info->info = info;
639
640 info->flags =
641 FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_IMAGEBLIT |
642 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
643 info->fbops = &dlfb_ops;
644 info->screen_base = rvmalloc(dev_info->screen_size);
645
646 if (info->screen_base == NULL) {
647 printk
648 ("cannot allocate framebuffer virtual memory of %d bytes\n",
649 dev_info->screen_size);
650 goto out0;
651 }
652
653 printk("screen base allocated !!!\n");
654
655 dev_info->backing_buffer = kzalloc(dev_info->screen_size, GFP_KERNEL);
656
657 if (!dev_info->backing_buffer) {
658 printk("non posso allocare il backing buffer\n");
659 }
660 //info->var = dev_info->si;
661
662 info->var.bits_per_pixel = 16;
663 info->var.activate = FB_ACTIVATE_TEST;
664 info->var.vmode = FB_VMODE_NONINTERLACED;
665
666 info->var.red.offset = 11;
667 info->var.red.length = 5;
668 info->var.red.msb_right = 0;
669
670 info->var.green.offset = 5;
671 info->var.green.length = 6;
672 info->var.green.msb_right = 0;
673
674 info->var.blue.offset = 0;
675 info->var.blue.length = 5;
676 info->var.blue.msb_right = 0;
677
678 //info->var.pixclock = (10000000 / FB_W * 1000 / FB_H)/2 ;
679
680 info->fix.smem_start = (unsigned long)info->screen_base;
681 info->fix.smem_len = PAGE_ALIGN(dev_info->screen_size);
682 memcpy(info->fix.id, "DisplayLink FB", 14);
683 info->fix.type = FB_TYPE_PACKED_PIXELS;
684 info->fix.visual = FB_VISUAL_TRUECOLOR;
685 info->fix.accel = info->flags;
686 info->fix.line_length = dev_info->line_length;
687
688 if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
689 goto out1;
690 }
691
692 printk("colormap allocated\n");
693 if (register_framebuffer(info) < 0) {
694 goto out2;
695 }
696
697 draw_rect(dev_info, 0, 0, dev_info->info->var.xres,
698 dev_info->info->var.yres, 0x30, 0xff, 0x30);
699
700 return 0;
701
702 out2:
703 fb_dealloc_cmap(&info->cmap);
704 out1:
705 rvfree(info->screen_base, dev_info->screen_size);
706 out0:
707 framebuffer_release(info);
708 out:
709 usb_set_intfdata(interface, NULL);
710 usb_put_dev(dev_info->udev);
711 kfree(dev_info);
712 return -ENOMEM;
713
714}
715
716static void dlfb_disconnect(struct usb_interface *interface)
717{
718 struct dlfb_data *dev_info = usb_get_intfdata(interface);
719
720 mutex_unlock(&dev_info->bulk_mutex);
721
722 usb_kill_urb(dev_info->tx_urb);
723 usb_free_urb(dev_info->tx_urb);
724 usb_set_intfdata(interface, NULL);
725 usb_put_dev(dev_info->udev);
726
727 if (dev_info->info) {
728 unregister_framebuffer(dev_info->info);
729 fb_dealloc_cmap(&dev_info->info->cmap);
730 rvfree(dev_info->info->screen_base, dev_info->screen_size);
731 kfree(dev_info->backing_buffer);
732 framebuffer_release(dev_info->info);
733
734 }
735
736 kfree(dev_info);
737
738 printk("DisplayLink device disconnected\n");
739}
740
741static struct usb_driver dlfb_driver = {
742 .name = "udlfb",
743 .probe = dlfb_probe,
744 .disconnect = dlfb_disconnect,
745 .id_table = id_table,
746};
747
748static int __init dlfb_init(void)
749{
750 int res;
751
752 dlfb_init_modes();
753
754 res = usb_register(&dlfb_driver);
755 if (res)
756 err("usb_register failed. Error number %d", res);
757
758 printk("VMODES initialized\n");
759
760 return res;
761}
762
763static void __exit dlfb_exit(void)
764{
765 usb_deregister(&dlfb_driver);
766}
767
768module_init(dlfb_init);
769module_exit(dlfb_exit);
770
771MODULE_AUTHOR("Roberto De Ioris <roberto@unbit.it>");
772MODULE_DESCRIPTION(DRIVER_VERSION);
773MODULE_LICENSE("GPL");