+#define TMPBUFLEN 2048
+
+static ssize_t
+stifb_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+ struct inode *inode = file->f_dentry->d_inode;
+ int fbidx = iminor(inode);
+ struct fb_info *info = registered_fb[fbidx];
+ char tmpbuf[TMPBUFLEN];
+
+ if (!info || ! info->screen_base)
+ return -ENODEV;
+
+ if (p >= info->fix.smem_len)
+ return 0;
+ if (count >= info->fix.smem_len)
+ count = info->fix.smem_len;
+ if (count + p > info->fix.smem_len)
+ count = info->fix.smem_len - p;
+ if (count > sizeof(tmpbuf))
+ count = sizeof(tmpbuf);
+ if (count) {
+ char *base_addr;
+
+ base_addr = info->screen_base;
+ memcpy_fromio(&tmpbuf, base_addr+p, count);
+ count -= copy_to_user(buf, &tmpbuf, count);
+ if (!count)
+ return -EFAULT;
+ *ppos += count;
+ }
+ return count;
+}
+
+static ssize_t
+stifb_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int fbidx = iminor(inode);
+ struct fb_info *info = registered_fb[fbidx];
+ unsigned long p = *ppos;
+ size_t c;
+ int err;
+ char tmpbuf[TMPBUFLEN];
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ if (p > info->fix.smem_len)
+ return -ENOSPC;
+ if (count >= info->fix.smem_len)
+ count = info->fix.smem_len;
+ err = 0;
+ if (count + p > info->fix.smem_len) {
+ count = info->fix.smem_len - p;
+ err = -ENOSPC;
+ }
+
+ p += (unsigned long)info->screen_base;
+ c = count;
+ while (c) {
+ int len = c > sizeof(tmpbuf) ? sizeof(tmpbuf) : c;
+ err = -EFAULT;
+ if (copy_from_user(&tmpbuf, buf, len))
+ break;
+ memcpy_toio(p, &tmpbuf, len);
+ c -= len;
+ p += len;
+ buf += len;
+ *ppos += len;
+ }
+ if (count-c)
+ return (count-c);
+ return err;
+}
+