aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbmem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r--drivers/video/fbmem.c299
1 files changed, 281 insertions, 18 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index e2667ddab3f1..9f180096c896 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -14,6 +14,7 @@
14#include <linux/config.h> 14#include <linux/config.h>
15#include <linux/module.h> 15#include <linux/module.h>
16 16
17#include <linux/compat.h>
17#include <linux/types.h> 18#include <linux/types.h>
18#include <linux/errno.h> 19#include <linux/errno.h>
19#include <linux/sched.h> 20#include <linux/sched.h>
@@ -323,9 +324,103 @@ static struct logo_data {
323 const struct linux_logo *logo; 324 const struct linux_logo *logo;
324} fb_logo; 325} fb_logo;
325 326
326int fb_prepare_logo(struct fb_info *info) 327static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
328{
329 u32 size = width * height, i;
330
331 out += size - 1;
332
333 for (i = size; i--; )
334 *out-- = *in++;
335}
336
337static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
338{
339 int i, j, w = width - 1;
340
341 for (i = 0; i < height; i++)
342 for (j = 0; j < width; j++)
343 out[height * j + w - i] = *in++;
344}
345
346static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
347{
348 int i, j, w = width - 1;
349
350 for (i = 0; i < height; i++)
351 for (j = 0; j < width; j++)
352 out[height * (w - j) + i] = *in++;
353}
354
355static void fb_rotate_logo(struct fb_info *info, u8 *dst,
356 struct fb_image *image, int rotate)
357{
358 u32 tmp;
359
360 if (rotate == FB_ROTATE_UD) {
361 image->dx = info->var.xres - image->width;
362 image->dy = info->var.yres - image->height;
363 fb_rotate_logo_ud(image->data, dst, image->width,
364 image->height);
365 } else if (rotate == FB_ROTATE_CW) {
366 tmp = image->width;
367 image->width = image->height;
368 image->height = tmp;
369 image->dx = info->var.xres - image->height;
370 fb_rotate_logo_cw(image->data, dst, image->width,
371 image->height);
372 } else if (rotate == FB_ROTATE_CCW) {
373 tmp = image->width;
374 image->width = image->height;
375 image->height = tmp;
376 image->dy = info->var.yres - image->width;
377 fb_rotate_logo_ccw(image->data, dst, image->width,
378 image->height);
379 }
380
381 image->data = dst;
382}
383
384static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
385 int rotate)
386{
387 int x;
388
389 if (rotate == FB_ROTATE_UR) {
390 for (x = 0; x < num_online_cpus() &&
391 x * (fb_logo.logo->width + 8) <=
392 info->var.xres - fb_logo.logo->width; x++) {
393 info->fbops->fb_imageblit(info, image);
394 image->dx += fb_logo.logo->width + 8;
395 }
396 } else if (rotate == FB_ROTATE_UD) {
397 for (x = 0; x < num_online_cpus() &&
398 x * (fb_logo.logo->width + 8) <=
399 info->var.xres - fb_logo.logo->width; x++) {
400 info->fbops->fb_imageblit(info, image);
401 image->dx -= fb_logo.logo->width + 8;
402 }
403 } else if (rotate == FB_ROTATE_CW) {
404 for (x = 0; x < num_online_cpus() &&
405 x * (fb_logo.logo->width + 8) <=
406 info->var.yres - fb_logo.logo->width; x++) {
407 info->fbops->fb_imageblit(info, image);
408 image->dy += fb_logo.logo->width + 8;
409 }
410 } else if (rotate == FB_ROTATE_CCW) {
411 for (x = 0; x < num_online_cpus() &&
412 x * (fb_logo.logo->width + 8) <=
413 info->var.yres - fb_logo.logo->width; x++) {
414 info->fbops->fb_imageblit(info, image);
415 image->dy -= fb_logo.logo->width + 8;
416 }
417 }
418}
419
420int fb_prepare_logo(struct fb_info *info, int rotate)
327{ 421{
328 int depth = fb_get_color_depth(&info->var, &info->fix); 422 int depth = fb_get_color_depth(&info->var, &info->fix);
423 int yres;
329 424
330 memset(&fb_logo, 0, sizeof(struct logo_data)); 425 memset(&fb_logo, 0, sizeof(struct logo_data));
331 426
@@ -358,10 +453,16 @@ int fb_prepare_logo(struct fb_info *info)
358 /* Return if no suitable logo was found */ 453 /* Return if no suitable logo was found */
359 fb_logo.logo = fb_find_logo(depth); 454 fb_logo.logo = fb_find_logo(depth);
360 455
361 if (!fb_logo.logo || fb_logo.logo->height > info->var.yres) { 456 if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD)
457 yres = info->var.yres;
458 else
459 yres = info->var.xres;
460
461 if (fb_logo.logo && fb_logo.logo->height > yres) {
362 fb_logo.logo = NULL; 462 fb_logo.logo = NULL;
363 return 0; 463 return 0;
364 } 464 }
465
365 /* What depth we asked for might be different from what we get */ 466 /* What depth we asked for might be different from what we get */
366 if (fb_logo.logo->type == LINUX_LOGO_CLUT224) 467 if (fb_logo.logo->type == LINUX_LOGO_CLUT224)
367 fb_logo.depth = 8; 468 fb_logo.depth = 8;
@@ -372,12 +473,11 @@ int fb_prepare_logo(struct fb_info *info)
372 return fb_logo.logo->height; 473 return fb_logo.logo->height;
373} 474}
374 475
375int fb_show_logo(struct fb_info *info) 476int fb_show_logo(struct fb_info *info, int rotate)
376{ 477{
377 u32 *palette = NULL, *saved_pseudo_palette = NULL; 478 u32 *palette = NULL, *saved_pseudo_palette = NULL;
378 unsigned char *logo_new = NULL; 479 unsigned char *logo_new = NULL, *logo_rotate = NULL;
379 struct fb_image image; 480 struct fb_image image;
380 int x;
381 481
382 /* Return if the frame buffer is not mapped or suspended */ 482 /* Return if the frame buffer is not mapped or suspended */
383 if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING) 483 if (fb_logo.logo == NULL || info->state != FBINFO_STATE_RUNNING)
@@ -417,25 +517,30 @@ int fb_show_logo(struct fb_info *info)
417 fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth); 517 fb_set_logo(info, fb_logo.logo, logo_new, fb_logo.depth);
418 } 518 }
419 519
520 image.dx = 0;
521 image.dy = 0;
420 image.width = fb_logo.logo->width; 522 image.width = fb_logo.logo->width;
421 image.height = fb_logo.logo->height; 523 image.height = fb_logo.logo->height;
422 image.dy = 0;
423 524
424 for (x = 0; x < num_online_cpus() * (fb_logo.logo->width + 8) && 525 if (rotate) {
425 x <= info->var.xres-fb_logo.logo->width; x += (fb_logo.logo->width + 8)) { 526 logo_rotate = kmalloc(fb_logo.logo->width *
426 image.dx = x; 527 fb_logo.logo->height, GFP_KERNEL);
427 info->fbops->fb_imageblit(info, &image); 528 if (logo_rotate)
529 fb_rotate_logo(info, logo_rotate, &image, rotate);
428 } 530 }
429 531
532 fb_do_show_logo(info, &image, rotate);
533
430 kfree(palette); 534 kfree(palette);
431 if (saved_pseudo_palette != NULL) 535 if (saved_pseudo_palette != NULL)
432 info->pseudo_palette = saved_pseudo_palette; 536 info->pseudo_palette = saved_pseudo_palette;
433 kfree(logo_new); 537 kfree(logo_new);
538 kfree(logo_rotate);
434 return fb_logo.logo->height; 539 return fb_logo.logo->height;
435} 540}
436#else 541#else
437int fb_prepare_logo(struct fb_info *info) { return 0; } 542int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
438int fb_show_logo(struct fb_info *info) { return 0; } 543int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
439#endif /* CONFIG_LOGO */ 544#endif /* CONFIG_LOGO */
440 545
441static int fbmem_read_proc(char *buf, char **start, off_t offset, 546static int fbmem_read_proc(char *buf, char **start, off_t offset,
@@ -829,18 +934,154 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
829} 934}
830 935
831#ifdef CONFIG_COMPAT 936#ifdef CONFIG_COMPAT
937struct fb_fix_screeninfo32 {
938 char id[16];
939 compat_caddr_t smem_start;
940 u32 smem_len;
941 u32 type;
942 u32 type_aux;
943 u32 visual;
944 u16 xpanstep;
945 u16 ypanstep;
946 u16 ywrapstep;
947 u32 line_length;
948 compat_caddr_t mmio_start;
949 u32 mmio_len;
950 u32 accel;
951 u16 reserved[3];
952};
953
954struct fb_cmap32 {
955 u32 start;
956 u32 len;
957 compat_caddr_t red;
958 compat_caddr_t green;
959 compat_caddr_t blue;
960 compat_caddr_t transp;
961};
962
963static int fb_getput_cmap(struct inode *inode, struct file *file,
964 unsigned int cmd, unsigned long arg)
965{
966 struct fb_cmap_user __user *cmap;
967 struct fb_cmap32 __user *cmap32;
968 __u32 data;
969 int err;
970
971 cmap = compat_alloc_user_space(sizeof(*cmap));
972 cmap32 = compat_ptr(arg);
973
974 if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32)))
975 return -EFAULT;
976
977 if (get_user(data, &cmap32->red) ||
978 put_user(compat_ptr(data), &cmap->red) ||
979 get_user(data, &cmap32->green) ||
980 put_user(compat_ptr(data), &cmap->green) ||
981 get_user(data, &cmap32->blue) ||
982 put_user(compat_ptr(data), &cmap->blue) ||
983 get_user(data, &cmap32->transp) ||
984 put_user(compat_ptr(data), &cmap->transp))
985 return -EFAULT;
986
987 err = fb_ioctl(inode, file, cmd, (unsigned long) cmap);
988
989 if (!err) {
990 if (copy_in_user(&cmap32->start,
991 &cmap->start,
992 2 * sizeof(__u32)))
993 err = -EFAULT;
994 }
995 return err;
996}
997
998static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix,
999 struct fb_fix_screeninfo32 __user *fix32)
1000{
1001 __u32 data;
1002 int err;
1003
1004 err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id));
1005
1006 data = (__u32) (unsigned long) fix->smem_start;
1007 err |= put_user(data, &fix32->smem_start);
1008
1009 err |= put_user(fix->smem_len, &fix32->smem_len);
1010 err |= put_user(fix->type, &fix32->type);
1011 err |= put_user(fix->type_aux, &fix32->type_aux);
1012 err |= put_user(fix->visual, &fix32->visual);
1013 err |= put_user(fix->xpanstep, &fix32->xpanstep);
1014 err |= put_user(fix->ypanstep, &fix32->ypanstep);
1015 err |= put_user(fix->ywrapstep, &fix32->ywrapstep);
1016 err |= put_user(fix->line_length, &fix32->line_length);
1017
1018 data = (__u32) (unsigned long) fix->mmio_start;
1019 err |= put_user(data, &fix32->mmio_start);
1020
1021 err |= put_user(fix->mmio_len, &fix32->mmio_len);
1022 err |= put_user(fix->accel, &fix32->accel);
1023 err |= copy_to_user(fix32->reserved, fix->reserved,
1024 sizeof(fix->reserved));
1025
1026 return err;
1027}
1028
1029static int fb_get_fscreeninfo(struct inode *inode, struct file *file,
1030 unsigned int cmd, unsigned long arg)
1031{
1032 mm_segment_t old_fs;
1033 struct fb_fix_screeninfo fix;
1034 struct fb_fix_screeninfo32 __user *fix32;
1035 int err;
1036
1037 fix32 = compat_ptr(arg);
1038
1039 old_fs = get_fs();
1040 set_fs(KERNEL_DS);
1041 err = fb_ioctl(inode, file, cmd, (unsigned long) &fix);
1042 set_fs(old_fs);
1043
1044 if (!err)
1045 err = do_fscreeninfo_to_user(&fix, fix32);
1046
1047 return err;
1048}
1049
832static long 1050static long
833fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 1051fb_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
834{ 1052{
835 int fbidx = iminor(file->f_dentry->d_inode); 1053 struct inode *inode = file->f_dentry->d_inode;
1054 int fbidx = iminor(inode);
836 struct fb_info *info = registered_fb[fbidx]; 1055 struct fb_info *info = registered_fb[fbidx];
837 struct fb_ops *fb = info->fbops; 1056 struct fb_ops *fb = info->fbops;
838 long ret; 1057 long ret = -ENOIOCTLCMD;
839 1058
840 if (fb->fb_compat_ioctl == NULL)
841 return -ENOIOCTLCMD;
842 lock_kernel(); 1059 lock_kernel();
843 ret = fb->fb_compat_ioctl(file, cmd, arg, info); 1060 switch(cmd) {
1061 case FBIOGET_VSCREENINFO:
1062 case FBIOPUT_VSCREENINFO:
1063 case FBIOPAN_DISPLAY:
1064 case FBIOGET_CON2FBMAP:
1065 case FBIOPUT_CON2FBMAP:
1066 arg = (unsigned long) compat_ptr(arg);
1067 case FBIOBLANK:
1068 ret = fb_ioctl(inode, file, cmd, arg);
1069 break;
1070
1071 case FBIOGET_FSCREENINFO:
1072 ret = fb_get_fscreeninfo(inode, file, cmd, arg);
1073 break;
1074
1075 case FBIOGETCMAP:
1076 case FBIOPUTCMAP:
1077 ret = fb_getput_cmap(inode, file, cmd, arg);
1078 break;
1079
1080 default:
1081 if (fb->fb_compat_ioctl)
1082 ret = fb->fb_compat_ioctl(file, cmd, arg, info);
1083 break;
1084 }
844 unlock_kernel(); 1085 unlock_kernel();
845 return ret; 1086 return ret;
846} 1087}
@@ -1215,6 +1456,28 @@ int fb_new_modelist(struct fb_info *info)
1215 return err; 1456 return err;
1216} 1457}
1217 1458
1459/**
1460 * fb_con_duit - user<->fbcon passthrough
1461 * @info: struct fb_info
1462 * @event: notification event to be passed to fbcon
1463 * @data: private data
1464 *
1465 * DESCRIPTION
1466 * This function is an fbcon-user event passing channel
1467 * which bypasses fbdev. This is hopefully temporary
1468 * until a user interface for fbcon is created
1469 */
1470int fb_con_duit(struct fb_info *info, int event, void *data)
1471{
1472 struct fb_event evnt;
1473
1474 evnt.info = info;
1475 evnt.data = data;
1476
1477 return notifier_call_chain(&fb_notifier_list, event, &evnt);
1478}
1479EXPORT_SYMBOL(fb_con_duit);
1480
1218static char *video_options[FB_MAX]; 1481static char *video_options[FB_MAX];
1219static int ofonly; 1482static int ofonly;
1220 1483