diff options
author | James Hogan <james@albanarts.com> | 2010-10-27 18:33:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-27 21:03:08 -0400 |
commit | f11b478d461b7113eb4603b3914aaf15b7788e87 (patch) | |
tree | 84e673927a071c64658d8b24ae423de86948b573 /drivers/video/fbmem.c | |
parent | c9c62dce35e7fc54beebafb071393a0008989e49 (diff) |
fbmem: fix fb_read, fb_write unaligned accesses
fb_{read,write} access the framebuffer using lots of fb_{read,write}l's
but don't check that the file position is aligned which can cause problems
on some architectures which do not support unaligned accesses.
Since the operations are essentially memcpy_{from,to}io, new
fb_memcpy_{from,to}fb macros have been defined and these are used instead.
For Sparc, fb_{read,write} macros use sbus_{read,write}, so this defines
new sbus_memcpy_{from,to}io functions the same as memcpy_{from,to}io but
using sbus_{read,write}b instead of {read,write}b.
Signed-off-by: James Hogan <james@albanarts.com>
Acked-by: David S. Miller <davem@davemloft.net>
Acked-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r-- | drivers/video/fbmem.c | 46 |
1 files changed, 14 insertions, 32 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index a43442341ddd..0e6aa3d96a42 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -697,9 +697,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
697 | struct inode *inode = file->f_path.dentry->d_inode; | 697 | struct inode *inode = file->f_path.dentry->d_inode; |
698 | int fbidx = iminor(inode); | 698 | int fbidx = iminor(inode); |
699 | struct fb_info *info = registered_fb[fbidx]; | 699 | struct fb_info *info = registered_fb[fbidx]; |
700 | u32 *buffer, *dst; | 700 | u8 *buffer, *dst; |
701 | u32 __iomem *src; | 701 | u8 __iomem *src; |
702 | int c, i, cnt = 0, err = 0; | 702 | int c, cnt = 0, err = 0; |
703 | unsigned long total_size; | 703 | unsigned long total_size; |
704 | 704 | ||
705 | if (!info || ! info->screen_base) | 705 | if (!info || ! info->screen_base) |
@@ -730,7 +730,7 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
730 | if (!buffer) | 730 | if (!buffer) |
731 | return -ENOMEM; | 731 | return -ENOMEM; |
732 | 732 | ||
733 | src = (u32 __iomem *) (info->screen_base + p); | 733 | src = (u8 __iomem *) (info->screen_base + p); |
734 | 734 | ||
735 | if (info->fbops->fb_sync) | 735 | if (info->fbops->fb_sync) |
736 | info->fbops->fb_sync(info); | 736 | info->fbops->fb_sync(info); |
@@ -738,17 +738,9 @@ fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
738 | while (count) { | 738 | while (count) { |
739 | c = (count > PAGE_SIZE) ? PAGE_SIZE : count; | 739 | c = (count > PAGE_SIZE) ? PAGE_SIZE : count; |
740 | dst = buffer; | 740 | dst = buffer; |
741 | for (i = c >> 2; i--; ) | 741 | fb_memcpy_fromfb(dst, src, c); |
742 | *dst++ = fb_readl(src++); | 742 | dst += c; |
743 | if (c & 3) { | 743 | src += c; |
744 | u8 *dst8 = (u8 *) dst; | ||
745 | u8 __iomem *src8 = (u8 __iomem *) src; | ||
746 | |||
747 | for (i = c & 3; i--;) | ||
748 | *dst8++ = fb_readb(src8++); | ||
749 | |||
750 | src = (u32 __iomem *) src8; | ||
751 | } | ||
752 | 744 | ||
753 | if (copy_to_user(buf, buffer, c)) { | 745 | if (copy_to_user(buf, buffer, c)) { |
754 | err = -EFAULT; | 746 | err = -EFAULT; |
@@ -772,9 +764,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
772 | struct inode *inode = file->f_path.dentry->d_inode; | 764 | struct inode *inode = file->f_path.dentry->d_inode; |
773 | int fbidx = iminor(inode); | 765 | int fbidx = iminor(inode); |
774 | struct fb_info *info = registered_fb[fbidx]; | 766 | struct fb_info *info = registered_fb[fbidx]; |
775 | u32 *buffer, *src; | 767 | u8 *buffer, *src; |
776 | u32 __iomem *dst; | 768 | u8 __iomem *dst; |
777 | int c, i, cnt = 0, err = 0; | 769 | int c, cnt = 0, err = 0; |
778 | unsigned long total_size; | 770 | unsigned long total_size; |
779 | 771 | ||
780 | if (!info || !info->screen_base) | 772 | if (!info || !info->screen_base) |
@@ -811,7 +803,7 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
811 | if (!buffer) | 803 | if (!buffer) |
812 | return -ENOMEM; | 804 | return -ENOMEM; |
813 | 805 | ||
814 | dst = (u32 __iomem *) (info->screen_base + p); | 806 | dst = (u8 __iomem *) (info->screen_base + p); |
815 | 807 | ||
816 | if (info->fbops->fb_sync) | 808 | if (info->fbops->fb_sync) |
817 | info->fbops->fb_sync(info); | 809 | info->fbops->fb_sync(info); |
@@ -825,19 +817,9 @@ fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | |||
825 | break; | 817 | break; |
826 | } | 818 | } |
827 | 819 | ||
828 | for (i = c >> 2; i--; ) | 820 | fb_memcpy_tofb(dst, src, c); |
829 | fb_writel(*src++, dst++); | 821 | dst += c; |
830 | 822 | src += c; | |
831 | if (c & 3) { | ||
832 | u8 *src8 = (u8 *) src; | ||
833 | u8 __iomem *dst8 = (u8 __iomem *) dst; | ||
834 | |||
835 | for (i = c & 3; i--; ) | ||
836 | fb_writeb(*src8++, dst8++); | ||
837 | |||
838 | dst = (u32 __iomem *) dst8; | ||
839 | } | ||
840 | |||
841 | *ppos += c; | 823 | *ppos += c; |
842 | buf += c; | 824 | buf += c; |
843 | cnt += c; | 825 | cnt += c; |