summaryrefslogtreecommitdiffstats
path: root/drivers/char/vc_screen.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /drivers/char/vc_screen.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'drivers/char/vc_screen.c')
-rw-r--r--drivers/char/vc_screen.c164
1 files changed, 102 insertions, 62 deletions
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index b03118f78..71f4e2f84 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -14,24 +14,54 @@
* administrator can control access using file system permissions.
*
* aeb@cwi.nl - efter Friedas begravelse - 950211
+ *
+ * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
+ * - fixed some fatal of-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
+ * - making it working with multiple monitor patches
+ * - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
+#include <linux/config.h>
+
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/sched.h>
+#include <linux/interrupt.h>
#include <linux/mm.h>
+#include <linux/init.h>
#include <asm/uaccess.h>
#include "vt_kern.h"
#include "selection.h"
+#undef attr
+#undef org
+#undef addr
#define HEADER_SIZE 4
-static inline int
+static unsigned short
+func_scr_readw(unsigned short *org)
+{
+return scr_readw( org );
+}
+
+static void
+func_scr_writew(unsigned short val, unsigned short *org)
+{
+scr_writew( val, org );
+}
+
+static int
vcs_size(struct inode *inode)
{
- int size = video_num_lines * video_num_columns;
+ int size;
+#ifdef CONFIG_MULTIMON
+ int currcons = MINOR(inode->i_rdev) & 127;
+ /* Multimon patch */
+ if (!vc_cons[currcons].d) return 0;
+#endif
+ size= video_num_lines * video_num_columns;
if (MINOR(inode->i_rdev) & 128)
size = 2*size + HEADER_SIZE;
return size;
@@ -40,7 +70,8 @@ vcs_size(struct inode *inode)
static long long
vcs_lseek(struct inode *inode, struct file *file, long long offset, int orig)
{
- int size = vcs_size(inode);
+ int size;
+ size = vcs_size(inode);
switch (orig) {
case 0:
@@ -56,145 +87,154 @@ vcs_lseek(struct inode *inode, struct file *file, long long offset, int orig)
return -EINVAL;
}
if (file->f_pos < 0 || file->f_pos > size)
- return -EINVAL;
+ { file->f_pos = 0; return -EINVAL; }
return file->f_pos;
}
+#define RETURN( x ) { enable_bh( CONSOLE_BH ); return x; }
static long
vcs_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
{
- unsigned long p = file->f_pos;
- unsigned int cons = MINOR(inode->i_rdev);
+ int p = file->f_pos;
+ unsigned int currcons = MINOR(inode->i_rdev);
int viewed, attr, size, read;
char *buf0;
- unsigned short *org;
+ unsigned short *org = NULL;
- attr = (cons & 128);
- cons = (cons & 127);
- if (cons == 0) {
- cons = fg_console;
+ attr = (currcons & 128);
+ currcons = (currcons & 127);
+ disable_bh( CONSOLE_BH );
+ if (currcons == 0) {
+ currcons = fg_console;
viewed = 1;
} else {
- cons--;
+ currcons--;
viewed = 0;
}
- if (!vc_cons_allocated(cons))
- return -ENXIO;
+ if (!vc_cons_allocated(currcons))
+ RETURN( -ENXIO );
size = vcs_size(inode);
- if (p > size)
- return -EINVAL;
+ if (p < 0 || p > size)
+ RETURN( -EINVAL );
if (count > size - p)
count = size - p;
buf0 = buf;
if (!attr) {
- org = screen_pos(cons, p, viewed);
+ org = screen_pos(currcons, p, viewed);
while (count-- > 0)
- put_user(scr_readw(org++) & 0xff, buf++);
+ put_user(func_scr_readw(org++) & 0xff, buf++);
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
header[0] = (char) video_num_lines;
header[1] = (char) video_num_columns;
- getconsxy(cons, header+2);
- while (p < HEADER_SIZE && count-- > 0)
- put_user(header[p++], buf++);
+ getconsxy(currcons, header+2);
+ while (p < HEADER_SIZE && count > 0)
+ { count--; put_user(header[p++], buf++); }
+ }
+ if (count > 0) {
+ p -= HEADER_SIZE;
+ org = screen_pos(currcons, p/2, viewed);
+ if ((p & 1) && count > 0)
+ { count--; put_user(func_scr_readw(org++) >> 8, buf++); }
}
- p -= HEADER_SIZE;
- org = screen_pos(cons, p/2, viewed);
- if ((p & 1) && count-- > 0)
- put_user(scr_readw(org++) >> 8, buf++);
while (count > 1) {
- put_user(scr_readw(org++), (unsigned short *) buf);
+ put_user(func_scr_readw(org++), (unsigned short *) buf);
buf += 2;
count -= 2;
}
if (count > 0)
- put_user(scr_readw(org) & 0xff, buf++);
+ put_user(func_scr_readw(org) & 0xff, buf++);
}
read = buf - buf0;
file->f_pos += read;
- return read;
+ RETURN( read );
}
static long
vcs_write(struct inode *inode, struct file *file, const char *buf, unsigned long count)
{
- unsigned long p = file->f_pos;
- unsigned int cons = MINOR(inode->i_rdev);
+ int p = file->f_pos;
+ unsigned int currcons = MINOR(inode->i_rdev);
int viewed, attr, size, written;
const char *buf0;
- unsigned short *org;
+ unsigned short *org = NULL;
- attr = (cons & 128);
- cons = (cons & 127);
- if (cons == 0) {
- cons = fg_console;
+ attr = (currcons & 128);
+ currcons = (currcons & 127);
+ disable_bh( CONSOLE_BH );
+ if (currcons == 0) {
+ currcons = fg_console;
viewed = 1;
} else {
- cons--;
+ currcons--;
viewed = 0;
}
- if (!vc_cons_allocated(cons))
- return -ENXIO;
+ if (!vc_cons_allocated(currcons))
+ RETURN( -ENXIO );
size = vcs_size(inode);
- if (p > size)
- return -EINVAL;
+ if (p < 0 || p > size)
+ RETURN( -EINVAL );
if (count > size - p)
count = size - p;
buf0 = buf;
if (!attr) {
- org = screen_pos(cons, p, viewed);
- while (count-- > 0) {
+ org = screen_pos(currcons, p, viewed);
+ while (count > 0) {
unsigned char c;
+ count--;
get_user(c, (const unsigned char*)buf++);
- scr_writew((scr_readw(org) & 0xff00) | c, org);
+ func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
org++;
}
} else {
if (p < HEADER_SIZE) {
char header[HEADER_SIZE];
- getconsxy(cons, header+2);
- while (p < HEADER_SIZE && count-- > 0)
- get_user(header[p++], buf++);
+ getconsxy(currcons, header+2);
+ while (p < HEADER_SIZE && count > 0)
+ { count--; get_user(header[p++], buf++); }
if (!viewed)
- putconsxy(cons, header+2);
+ putconsxy(currcons, header+2);
}
- p -= HEADER_SIZE;
- org = screen_pos(cons, p/2, viewed);
- if ((p & 1) && count-- > 0) {
- char c;
- get_user(c,buf++);
- scr_writew((c << 8) |
- (scr_readw(org) & 0xff), org);
- org++;
+ if (count > 0) {
+ p -= HEADER_SIZE;
+ org = screen_pos(currcons, p/2, viewed);
+ if ((p & 1) && count > 0) {
+ char c;
+ count--;
+ get_user(c,buf++);
+ func_scr_writew((c << 8) |
+ (func_scr_readw(org) & 0xff), org);
+ org++;
+ }
}
while (count > 1) {
unsigned short w;
get_user(w, (const unsigned short *) buf);
- scr_writew(w, org++);
+ func_scr_writew(w, org++);
buf += 2;
count -= 2;
}
if (count > 0) {
unsigned char c;
get_user(c, (const unsigned char*)buf++);
- scr_writew((scr_readw(org) & 0xff00) | c, org);
+ func_scr_writew((func_scr_readw(org) & 0xff00) | c, org);
}
}
written = buf - buf0;
file->f_pos += written;
- return written;
+ RETURN( written );
}
static int
vcs_open(struct inode *inode, struct file *filp)
{
- unsigned int cons = (MINOR(inode->i_rdev) & 127);
- if(cons && !vc_cons_allocated(cons-1))
+ unsigned int currcons = (MINOR(inode->i_rdev) & 127);
+ if(currcons && !vc_cons_allocated(currcons-1))
return -ENXIO;
return 0;
}
@@ -204,7 +244,7 @@ static struct file_operations vcs_fops = {
vcs_read, /* read */
vcs_write, /* write */
NULL, /* readdir */
- NULL, /* select */
+ NULL, /* poll */
NULL, /* ioctl */
NULL, /* mmap */
vcs_open, /* open */
@@ -212,7 +252,7 @@ static struct file_operations vcs_fops = {
NULL /* fsync */
};
-int vcs_init(void)
+__initfunc(int vcs_init(void))
{
int error;