| Antonino A. Daplas | 09aaf26 | 2007-05-08 00:39:03 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * linux/drivers/video/fb_sys_read.c - Generic file operations where | 
 | 3 |  * framebuffer is in system RAM | 
 | 4 |  * | 
 | 5 |  * Copyright (C) 2007 Antonino Daplas <adaplas@pol.net> | 
 | 6 |  * | 
 | 7 |  * This file is subject to the terms and conditions of the GNU General Public | 
 | 8 |  * License.  See the file COPYING in the main directory of this archive | 
 | 9 |  * for more details. | 
 | 10 |  * | 
 | 11 |  */ | 
 | 12 | #include <linux/fb.h> | 
 | 13 | #include <linux/module.h> | 
| Krzysztof Helt | 84902b7 | 2007-10-16 01:29:04 -0700 | [diff] [blame] | 14 | #include <linux/uaccess.h> | 
| Antonino A. Daplas | 09aaf26 | 2007-05-08 00:39:03 -0700 | [diff] [blame] | 15 |  | 
 | 16 | ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, | 
 | 17 | 		    loff_t *ppos) | 
 | 18 | { | 
 | 19 | 	unsigned long p = *ppos; | 
 | 20 | 	void *src; | 
 | 21 | 	int err = 0; | 
 | 22 | 	unsigned long total_size; | 
 | 23 |  | 
 | 24 | 	if (info->state != FBINFO_STATE_RUNNING) | 
 | 25 | 		return -EPERM; | 
 | 26 |  | 
 | 27 | 	total_size = info->screen_size; | 
 | 28 |  | 
 | 29 | 	if (total_size == 0) | 
 | 30 | 		total_size = info->fix.smem_len; | 
 | 31 |  | 
 | 32 | 	if (p >= total_size) | 
 | 33 | 		return 0; | 
 | 34 |  | 
 | 35 | 	if (count >= total_size) | 
 | 36 | 		count = total_size; | 
 | 37 |  | 
 | 38 | 	if (count + p > total_size) | 
 | 39 | 		count = total_size - p; | 
 | 40 |  | 
 | 41 | 	src = (void __force *)(info->screen_base + p); | 
 | 42 |  | 
 | 43 | 	if (info->fbops->fb_sync) | 
 | 44 | 		info->fbops->fb_sync(info); | 
 | 45 |  | 
 | 46 | 	if (copy_to_user(buf, src, count)) | 
 | 47 | 		err = -EFAULT; | 
 | 48 |  | 
 | 49 | 	if  (!err) | 
 | 50 | 		*ppos += count; | 
 | 51 |  | 
 | 52 | 	return (err) ? err : count; | 
 | 53 | } | 
 | 54 | EXPORT_SYMBOL_GPL(fb_sys_read); | 
 | 55 |  | 
 | 56 | ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, | 
 | 57 | 		     size_t count, loff_t *ppos) | 
 | 58 | { | 
 | 59 | 	unsigned long p = *ppos; | 
 | 60 | 	void *dst; | 
 | 61 | 	int err = 0; | 
 | 62 | 	unsigned long total_size; | 
 | 63 |  | 
 | 64 | 	if (info->state != FBINFO_STATE_RUNNING) | 
 | 65 | 		return -EPERM; | 
 | 66 |  | 
 | 67 | 	total_size = info->screen_size; | 
 | 68 |  | 
 | 69 | 	if (total_size == 0) | 
 | 70 | 		total_size = info->fix.smem_len; | 
 | 71 |  | 
 | 72 | 	if (p > total_size) | 
 | 73 | 		return -EFBIG; | 
 | 74 |  | 
 | 75 | 	if (count > total_size) { | 
 | 76 | 		err = -EFBIG; | 
 | 77 | 		count = total_size; | 
 | 78 | 	} | 
 | 79 |  | 
 | 80 | 	if (count + p > total_size) { | 
 | 81 | 		if (!err) | 
 | 82 | 			err = -ENOSPC; | 
 | 83 |  | 
 | 84 | 		count = total_size - p; | 
 | 85 | 	} | 
 | 86 |  | 
 | 87 | 	dst = (void __force *) (info->screen_base + p); | 
 | 88 |  | 
 | 89 | 	if (info->fbops->fb_sync) | 
 | 90 | 		info->fbops->fb_sync(info); | 
 | 91 |  | 
 | 92 | 	if (copy_from_user(dst, buf, count)) | 
 | 93 | 		err = -EFAULT; | 
 | 94 |  | 
 | 95 | 	if  (!err) | 
 | 96 | 		*ppos += count; | 
 | 97 |  | 
 | 98 | 	return (err) ? err : count; | 
 | 99 | } | 
 | 100 | EXPORT_SYMBOL_GPL(fb_sys_write); | 
 | 101 |  | 
 | 102 | MODULE_AUTHOR("Antonino Daplas <adaplas@pol.net>"); | 
 | 103 | MODULE_DESCRIPTION("Generic file read (fb in system RAM)"); | 
 | 104 | MODULE_LICENSE("GPL"); |