OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [vc_screen.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/drivers/char/vc_screen.c
3
 *
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)
7
 *            [minor: N]
8
 *
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.
12
 *            [minor: N+128]
13
 *
14
 * This replaces screendump and part of selection, so that the system
15
 * administrator can control access using file system permissions.
16
 *
17
 * aeb@cwi.nl - efter Friedas begravelse - 950211
18
 *
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
22
 */
23
 
24
#include <linux/config.h>
25
#include <linux/kernel.h>
26
#include <linux/major.h>
27
#include <linux/errno.h>
28
#include <linux/tty.h>
29
#include <linux/devfs_fs_kernel.h>
30
#include <linux/sched.h>
31
#include <linux/interrupt.h>
32
#include <linux/mm.h>
33
#include <linux/init.h>
34
#include <linux/vt_kern.h>
35
#include <linux/console_struct.h>
36
#include <linux/selection.h>
37
#include <linux/kbd_kern.h>
38
#include <linux/console.h>
39
#include <asm/uaccess.h>
40
#include <asm/byteorder.h>
41
#include <asm/unaligned.h>
42
 
43
#undef attr
44
#undef org
45
#undef addr
46
#define HEADER_SIZE     4
47
 
48
static int
49
vcs_size(struct inode *inode)
50
{
51
        int size;
52
        int currcons = MINOR(inode->i_rdev) & 127;
53
        if (currcons == 0)
54
                currcons = fg_console;
55
        else
56
                currcons--;
57
        if (!vc_cons_allocated(currcons))
58
                return -ENXIO;
59
 
60
        size = video_num_lines * video_num_columns;
61
 
62
        if (MINOR(inode->i_rdev) & 128)
63
                size = 2*size + HEADER_SIZE;
64
        return size;
65
}
66
 
67
static loff_t vcs_lseek(struct file *file, loff_t offset, int orig)
68
{
69
        int size = vcs_size(file->f_dentry->d_inode);
70
 
71
        switch (orig) {
72
                default:
73
                        return -EINVAL;
74
                case 2:
75
                        offset += size;
76
                        break;
77
                case 1:
78
                        offset += file->f_pos;
79
                case 0:
80
                        break;
81
        }
82
        if (offset < 0 || offset > size)
83
                return -EINVAL;
84
        file->f_pos = offset;
85
        return file->f_pos;
86
}
87
 
88
/* We share this temporary buffer with the console write code
89
 * so that we can easily avoid touching user space while holding the
90
 * console spinlock.
91
 */
92
extern char con_buf[PAGE_SIZE];
93
#define CON_BUF_SIZE    PAGE_SIZE
94
extern struct semaphore con_buf_sem;
95
 
96
static ssize_t
97
vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
98
{
99
        struct inode *inode = file->f_dentry->d_inode;
100
        unsigned int currcons = MINOR(inode->i_rdev);
101
        long pos = *ppos;
102
        long viewed, attr, read;
103
        int col, maxcol;
104
        unsigned short *org = NULL;
105
        ssize_t ret;
106
 
107
        down(&con_buf_sem);
108
 
109
        /* Select the proper current console and verify
110
         * sanity of the situation under the console lock.
111
         */
112
        acquire_console_sem();
113
 
114
        attr = (currcons & 128);
115
        currcons = (currcons & 127);
116
        if (currcons == 0) {
117
                currcons = fg_console;
118
                viewed = 1;
119
        } else {
120
                currcons--;
121
                viewed = 0;
122
        }
123
        ret = -ENXIO;
124
        if (!vc_cons_allocated(currcons))
125
                goto unlock_out;
126
 
127
        ret = -EINVAL;
128
        if (pos < 0)
129
                goto unlock_out;
130
        read = 0;
131
        ret = 0;
132
        while (count) {
133
                char *con_buf0, *con_buf_start;
134
                long this_round, size;
135
                ssize_t orig_count;
136
                long p = pos;
137
 
138
                /* Check whether we are above size each round,
139
                 * as copy_to_user at the end of this loop
140
                 * could sleep.
141
                 */
142
                size = vcs_size(inode);
143
                if (pos >= size)
144
                        break;
145
                if (count > size - pos)
146
                        count = size - pos;
147
 
148
                this_round = count;
149
                if (this_round > CON_BUF_SIZE)
150
                        this_round = CON_BUF_SIZE;
151
 
152
                /* Perform the whole read into the local con_buf.
153
                 * Then we can drop the console spinlock and safely
154
                 * attempt to move it to userspace.
155
                 */
156
 
157
                con_buf_start = con_buf0 = con_buf;
158
                orig_count = this_round;
159
                maxcol = video_num_columns;
160
                if (!attr) {
161
                        org = screen_pos(currcons, p, viewed);
162
                        col = p % maxcol;
163
                        p += maxcol - col;
164
                        while (this_round-- > 0) {
165
                                *con_buf0++ = (vcs_scr_readw(currcons, org++) & 0xff);
166
                                if (++col == maxcol) {
167
                                        org = screen_pos(currcons, p, viewed);
168
                                        col = 0;
169
                                        p += maxcol;
170
                                }
171
                        }
172
                } else {
173
                        if (p < HEADER_SIZE) {
174
                                size_t tmp_count;
175
 
176
                                con_buf0[0] = (char) video_num_lines;
177
                                con_buf0[1] = (char) video_num_columns;
178
                                getconsxy(currcons, con_buf0 + 2);
179
 
180
                                con_buf_start += p;
181
                                this_round += p;
182
                                if (this_round > CON_BUF_SIZE) {
183
                                        this_round = CON_BUF_SIZE;
184
                                        orig_count = this_round - p;
185
                                }
186
 
187
                                tmp_count = HEADER_SIZE;
188
                                if (tmp_count > this_round)
189
                                        tmp_count = this_round;
190
 
191
                                /* Advance state pointers and move on. */
192
                                this_round -= tmp_count;
193
                                p = HEADER_SIZE;
194
                                con_buf0 = con_buf + HEADER_SIZE;
195
                                /* If this_round >= 0, then p is even... */
196
                        } else if (p & 1) {
197
                                /* Skip first byte for output if start address is odd
198
                                 * Update region sizes up/down depending on free
199
                                 * space in buffer.
200
                                 */
201
                                con_buf_start++;
202
                                if (this_round < CON_BUF_SIZE)
203
                                        this_round++;
204
                                else
205
                                        orig_count--;
206
                        }
207
                        if (this_round > 0) {
208
                                unsigned short *tmp_buf = (unsigned short *)con_buf0;
209
 
210
                                p -= HEADER_SIZE;
211
                                p /= 2;
212
                                col = p % maxcol;
213
 
214
                                org = screen_pos(currcons, p, viewed);
215
                                p += maxcol - col;
216
 
217
                                /* Buffer has even length, so we can always copy
218
                                 * character + attribute. We do not copy last byte
219
                                 * to userspace if this_round is odd.
220
                                 */
221
                                this_round = (this_round + 1) >> 1;
222
 
223
                                while (this_round) {
224
                                        *tmp_buf++ = vcs_scr_readw(currcons, org++);
225
                                        this_round --;
226
                                        if (++col == maxcol) {
227
                                                org = screen_pos(currcons, p, viewed);
228
                                                col = 0;
229
                                                p += maxcol;
230
                                        }
231
                                }
232
                        }
233
                }
234
 
235
                /* Finally, release the console semaphore while we push
236
                 * all the data to userspace from our temporary buffer.
237
                 *
238
                 * AKPM: Even though it's a semaphore, we should drop it because
239
                 * the pagefault handling code may want to call printk().
240
                 */
241
 
242
                release_console_sem();
243
                ret = copy_to_user(buf, con_buf_start, orig_count);
244
                acquire_console_sem();
245
 
246
                if (ret) {
247
                        read += (orig_count - ret);
248
                        ret = -EFAULT;
249
                        break;
250
                }
251
                buf += orig_count;
252
                pos += orig_count;
253
                read += orig_count;
254
                count -= orig_count;
255
        }
256
        *ppos += read;
257
        if (read)
258
                ret = read;
259
unlock_out:
260
        release_console_sem();
261
        up(&con_buf_sem);
262
        return ret;
263
}
264
 
265
static ssize_t
266
vcs_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
267
{
268
        struct inode *inode = file->f_dentry->d_inode;
269
        unsigned int currcons = MINOR(inode->i_rdev);
270
        long pos = *ppos;
271
        long viewed, attr, size, written;
272
        char *con_buf0;
273
        int col, maxcol;
274
        u16 *org0 = NULL, *org = NULL;
275
        size_t ret;
276
 
277
        down(&con_buf_sem);
278
 
279
        /* Select the proper current console and verify
280
         * sanity of the situation under the console lock.
281
         */
282
        acquire_console_sem();
283
 
284
        attr = (currcons & 128);
285
        currcons = (currcons & 127);
286
 
287
        if (currcons == 0) {
288
                currcons = fg_console;
289
                viewed = 1;
290
        } else {
291
                currcons--;
292
                viewed = 0;
293
        }
294
        ret = -ENXIO;
295
        if (!vc_cons_allocated(currcons))
296
                goto unlock_out;
297
 
298
        size = vcs_size(inode);
299
        ret = -EINVAL;
300
        if (pos < 0 || pos > size)
301
                goto unlock_out;
302
        if (count > size - pos)
303
                count = size - pos;
304
        written = 0;
305
        while (count) {
306
                long this_round = count;
307
                size_t orig_count;
308
                long p;
309
 
310
                if (this_round > CON_BUF_SIZE)
311
                        this_round = CON_BUF_SIZE;
312
 
313
                /* Temporarily drop the console lock so that we can read
314
                 * in the write data from userspace safely.
315
                 */
316
                release_console_sem();
317
                ret = copy_from_user(con_buf, buf, this_round);
318
                acquire_console_sem();
319
 
320
                if (ret) {
321
                        this_round -= ret;
322
                        if (!this_round) {
323
                                /* Abort loop if no data were copied. Otherwise
324
                                 * fail with -EFAULT.
325
                                 */
326
                                if (written)
327
                                        break;
328
                                ret = -EFAULT;
329
                                goto unlock_out;
330
                        }
331
                }
332
 
333
                /* The vcs_size might have changed while we slept to grab
334
                 * the user buffer, so recheck.
335
                 * Return data written up to now on failure.
336
                 */
337
                size = vcs_size(inode);
338
                if (pos >= size)
339
                        break;
340
                if (this_round > size - pos)
341
                        this_round = size - pos;
342
 
343
                /* OK, now actually push the write to the console
344
                 * under the lock using the local kernel buffer.
345
                 */
346
 
347
                con_buf0 = con_buf;
348
                orig_count = this_round;
349
                maxcol = video_num_columns;
350
                p = pos;
351
                if (!attr) {
352
                        org0 = org = screen_pos(currcons, p, viewed);
353
                        col = p % maxcol;
354
                        p += maxcol - col;
355
 
356
                        while (this_round > 0) {
357
                                unsigned char c = *con_buf0++;
358
 
359
                                this_round--;
360
                                vcs_scr_writew(currcons,
361
                                               (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
362
                                org++;
363
                                if (++col == maxcol) {
364
                                        org = screen_pos(currcons, p, viewed);
365
                                        col = 0;
366
                                        p += maxcol;
367
                                }
368
                        }
369
                } else {
370
                        if (p < HEADER_SIZE) {
371
                                char header[HEADER_SIZE];
372
 
373
                                getconsxy(currcons, header + 2);
374
                                while (p < HEADER_SIZE && this_round > 0) {
375
                                        this_round--;
376
                                        header[p++] = *con_buf0++;
377
                                }
378
                                if (!viewed)
379
                                        putconsxy(currcons, header + 2);
380
                        }
381
                        p -= HEADER_SIZE;
382
                        col = (p/2) % maxcol;
383
                        if (this_round > 0) {
384
                                org0 = org = screen_pos(currcons, p/2, viewed);
385
                                if ((p & 1) && this_round > 0) {
386
                                        char c;
387
 
388
                                        this_round--;
389
                                        c = *con_buf0++;
390
#ifdef __BIG_ENDIAN
391
                                        vcs_scr_writew(currcons, c |
392
                                             (vcs_scr_readw(currcons, org) & 0xff00), org);
393
#else
394
                                        vcs_scr_writew(currcons, (c << 8) |
395
                                             (vcs_scr_readw(currcons, org) & 0xff), org);
396
#endif
397
                                        org++;
398
                                        p++;
399
                                        if (++col == maxcol) {
400
                                                org = screen_pos(currcons, p/2, viewed);
401
                                                col = 0;
402
                                        }
403
                                }
404
                                p /= 2;
405
                                p += maxcol - col;
406
                        }
407
                        while (this_round > 1) {
408
                                unsigned short w;
409
 
410
                                w = get_unaligned(((const unsigned short *)con_buf0));
411
                                vcs_scr_writew(currcons, w, org++);
412
                                con_buf0 += 2;
413
                                this_round -= 2;
414
                                if (++col == maxcol) {
415
                                        org = screen_pos(currcons, p, viewed);
416
                                        col = 0;
417
                                        p += maxcol;
418
                                }
419
                        }
420
                        if (this_round > 0) {
421
                                unsigned char c;
422
 
423
                                c = *con_buf0++;
424
#ifdef __BIG_ENDIAN
425
                                vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff) | (c << 8), org);
426
#else
427
                                vcs_scr_writew(currcons, (vcs_scr_readw(currcons, org) & 0xff00) | c, org);
428
#endif
429
                        }
430
                }
431
                count -= orig_count;
432
                written += orig_count;
433
                buf += orig_count;
434
                pos += orig_count;
435
                if (org0)
436
                        update_region(currcons, (unsigned long)(org0), org-org0);
437
        }
438
        *ppos += written;
439
        ret = written;
440
 
441
unlock_out:
442
        release_console_sem();
443
 
444
        up(&con_buf_sem);
445
 
446
        return ret;
447
}
448
 
449
static int
450
vcs_open(struct inode *inode, struct file *filp)
451
{
452
        unsigned int currcons = (MINOR(inode->i_rdev) & 127);
453
        if(currcons && !vc_cons_allocated(currcons-1))
454
                return -ENXIO;
455
        return 0;
456
}
457
 
458
static struct file_operations vcs_fops = {
459
        llseek:         vcs_lseek,
460
        read:           vcs_read,
461
        write:          vcs_write,
462
        open:           vcs_open,
463
};
464
 
465
static devfs_handle_t devfs_handle;
466
 
467
void vcs_make_devfs (unsigned int index, int unregister)
468
{
469
#ifdef CONFIG_DEVFS_FS
470
    char name[8];
471
 
472
    sprintf (name, "a%u", index + 1);
473
    if (unregister)
474
    {
475
        devfs_unregister ( devfs_find_handle (devfs_handle, name + 1, 0, 0,
476
                                              DEVFS_SPECIAL_CHR, 0) );
477
        devfs_unregister ( devfs_find_handle (devfs_handle, name, 0, 0,
478
                                              DEVFS_SPECIAL_CHR, 0) );
479
    }
480
    else
481
    {
482
        devfs_register (devfs_handle, name + 1, DEVFS_FL_DEFAULT,
483
                        VCS_MAJOR, index + 1,
484
                        S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
485
        devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT,
486
                        VCS_MAJOR, index + 129,
487
                        S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
488
    }
489
#endif /* CONFIG_DEVFS_FS */
490
}
491
 
492
int __init vcs_init(void)
493
{
494
        int error;
495
 
496
        error = devfs_register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
497
 
498
        if (error)
499
                printk("unable to get major %d for vcs device", VCS_MAJOR);
500
 
501
        devfs_handle = devfs_mk_dir (NULL, "vcc", NULL);
502
        devfs_register (devfs_handle, "0", DEVFS_FL_DEFAULT,
503
                        VCS_MAJOR, 0,
504
                        S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
505
        devfs_register (devfs_handle, "a", DEVFS_FL_DEFAULT,
506
                        VCS_MAJOR, 128,
507
                        S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
508
 
509
        return error;
510
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.