2 * linux/drivers/char/vc_screen.c
4 * Provide access to virtual console memory.
5 * /dev/vcs0: the screen as it is being viewed right now (possibly scrolled)
6 * /dev/vcsN: the screen of /dev/ttyN (1 <= N <= 63)
9 * /dev/vcsaN: idem, but including attributes, and prefixed with
10 * the 4 bytes lines,columns,x,y (as screendump used to give).
11 * Attribute/character pair is in native endianity.
14 * This replaces screendump and part of selection, so that the system
15 * administrator can control access using file system permissions.
17 * aeb@cwi.nl - efter Friedas begravelse - 950211
19 * machek@k332.feld.cvut.cz - modified not to send characters to wrong console
20 * - fixed some fatal off-by-one bugs (0-- no longer == -1 -> looping and looping and looping...)
21 * - making it shorter - scr_readw are macros which expand in PRETTY long code
24 #include <linux/kernel.h>
25 #include <linux/major.h>
26 #include <linux/errno.h>
27 #include <linux/tty.h>
28 #include <linux/sched.h>
29 #include <linux/interrupt.h>
31 #include <linux/init.h>
32 #include <linux/vt_kern.h>
33 #include <linux/console_struct.h>
34 #include <linux/selection.h>
35 #include <asm/uaccess.h>
36 #include <asm/byteorder.h>
44 vcs_size(struct inode
*inode
)
47 int currcons
= MINOR(inode
->i_rdev
) & 127;
49 currcons
= fg_console
;
52 if (!vc_cons_allocated(currcons
))
55 size
= video_num_lines
* video_num_columns
;
57 if (MINOR(inode
->i_rdev
) & 128)
58 size
= 2*size
+ HEADER_SIZE
;
62 static long long vcs_lseek(struct file
*file
, long long offset
, int orig
)
64 int size
= vcs_size(file
->f_dentry
->d_inode
);
73 offset
+= file
->f_pos
;
77 if (offset
< 0 || offset
> size
)
83 #define RETURN(x) { enable_bh(CONSOLE_BH); return x; }
85 vcs_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
87 struct inode
*inode
= file
->f_dentry
->d_inode
;
88 unsigned int currcons
= MINOR(inode
->i_rdev
);
90 long viewed
, attr
, size
, read
;
92 unsigned short *org
= NULL
;
94 attr
= (currcons
& 128);
95 currcons
= (currcons
& 127);
96 disable_bh(CONSOLE_BH
);
98 currcons
= fg_console
;
104 if (!vc_cons_allocated(currcons
))
107 size
= vcs_size(inode
);
108 if (p
< 0 || p
> size
)
110 if (count
> size
- p
)
115 org
= screen_pos(currcons
, p
, viewed
);
117 put_user(vcs_scr_readw(currcons
, org
++) & 0xff, buf
++);
119 if (p
< HEADER_SIZE
) {
120 char header
[HEADER_SIZE
];
121 header
[0] = (char) video_num_lines
;
122 header
[1] = (char) video_num_columns
;
123 getconsxy(currcons
, header
+2);
124 while (p
< HEADER_SIZE
&& count
> 0)
125 { count
--; put_user(header
[p
++], buf
++); }
129 org
= screen_pos(currcons
, p
/2, viewed
);
130 if ((p
& 1) && count
> 0)
132 { count
--; put_user(vcs_scr_readw(currcons
, org
++) & 0xff, buf
++); }
134 { count
--; put_user(vcs_scr_readw(currcons
, org
++) >> 8, buf
++); }
138 put_user(vcs_scr_readw(currcons
, org
++), (unsigned short *) buf
);
144 put_user(vcs_scr_readw(currcons
, org
) >> 8, buf
++);
146 put_user(vcs_scr_readw(currcons
, org
) & 0xff, buf
++);
155 vcs_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
157 struct inode
*inode
= file
->f_dentry
->d_inode
;
158 unsigned int currcons
= MINOR(inode
->i_rdev
);
160 long viewed
, attr
, size
, written
;
162 u16
*org0
= NULL
, *org
= NULL
;
164 attr
= (currcons
& 128);
165 currcons
= (currcons
& 127);
166 disable_bh(CONSOLE_BH
);
168 currcons
= fg_console
;
174 if (!vc_cons_allocated(currcons
))
177 size
= vcs_size(inode
);
178 if (p
< 0 || p
> size
)
180 if (count
> size
- p
)
185 org0
= org
= screen_pos(currcons
, p
, viewed
);
189 get_user(c
, (const unsigned char*)buf
++);
190 vcs_scr_writew(currcons
, (vcs_scr_readw(currcons
, org
) & 0xff00) | c
, org
);
194 if (p
< HEADER_SIZE
) {
195 char header
[HEADER_SIZE
];
196 getconsxy(currcons
, header
+2);
197 while (p
< HEADER_SIZE
&& count
> 0)
198 { count
--; get_user(header
[p
++], buf
++); }
200 putconsxy(currcons
, header
+2);
204 org0
= org
= screen_pos(currcons
, p
/2, viewed
);
205 if ((p
& 1) && count
> 0) {
210 vcs_scr_writew(currcons
, c
|
211 (vcs_scr_readw(currcons
, org
) & 0xff00), org
);
213 vcs_scr_writew(currcons
, (c
<< 8) |
214 (vcs_scr_readw(currcons
, org
) & 0xff), org
);
221 get_user(w
, (const unsigned short *) buf
);
222 vcs_scr_writew(currcons
, w
, org
++);
228 get_user(c
, (const unsigned char*)buf
++);
230 vcs_scr_writew(currcons
, (vcs_scr_readw(currcons
, org
) & 0xff) | (c
<< 8), org
);
232 vcs_scr_writew(currcons
, (vcs_scr_readw(currcons
, org
) & 0xff00) | c
, org
);
237 update_region(currcons
, (unsigned long)(org0
), org
-org0
);
238 written
= buf
- buf0
;
244 vcs_open(struct inode
*inode
, struct file
*filp
)
246 unsigned int currcons
= (MINOR(inode
->i_rdev
) & 127);
247 if(currcons
&& !vc_cons_allocated(currcons
-1))
252 static struct file_operations vcs_fops
= {
253 vcs_lseek
, /* lseek */
255 vcs_write
, /* write */
266 __initfunc(int vcs_init(void))
270 error
= register_chrdev(VCS_MAJOR
, "vcs", &vcs_fops
);
272 printk("unable to get major %d for vcs device", VCS_MAJOR
);