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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/drivers/char/console.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 */
6
 
7
/*
8
 * Hopefully this will be a rather complete VT102 implementation.
9
 *
10
 * Beeping thanks to John T Kohl.
11
 *
12
 * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
13
 *   Chars, and VT100 enhancements by Peter MacDonald.
14
 *
15
 * Copy and paste function by Andrew Haylett,
16
 *   some enhancements by Alessandro Rubini.
17
 *
18
 * Code to check for different video-cards mostly by Galen Hunt,
19
 * <g-hunt@ee.utah.edu>
20
 *
21
 * Rudimentary ISO 10646/Unicode/UTF-8 character set support by
22
 * Markus Kuhn, <mskuhn@immd4.informatik.uni-erlangen.de>.
23
 *
24
 * Dynamic allocation of consoles, aeb@cwi.nl, May 1994
25
 * Resizing of consoles, aeb, 940926
26
 *
27
 * Code for xterm like mouse click reporting by Peter Orbaek 20-Jul-94
28
 * <poe@daimi.aau.dk>
29
 *
30
 * User-defined bell sound, new setterm control sequences and printk
31
 * redirection by Martin Mares <mj@k332.feld.cvut.cz> 19-Nov-95
32
 *
33
 * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
34
 *
35
 * Merge with the abstract console driver by Geert Uytterhoeven
36
 * <geert@linux-m68k.org>, Jan 1997.
37
 *
38
 *   Original m68k console driver modifications by
39
 *
40
 *     - Arno Griffioen <arno@usn.nl>
41
 *     - David Carter <carter@cs.bris.ac.uk>
42
 *
43
 *   Note that the abstract console driver allows all consoles to be of
44
 *   potentially different sizes, so the following variables depend on the
45
 *   current console (currcons):
46
 *
47
 *     - video_num_columns
48
 *     - video_num_lines
49
 *     - video_size_row
50
 *     - can_do_color
51
 *
52
 *   The abstract console driver provides a generic interface for a text
53
 *   console. It supports VGA text mode, frame buffer based graphical consoles
54
 *   and special graphics processors that are only accessible through some
55
 *   registers (e.g. a TMS340x0 GSP).
56
 *
57
 *   The interface to the hardware is specified using a special structure
58
 *   (struct consw) which contains function pointers to console operations
59
 *   (see <linux/console.h> for more information).
60
 *
61
 * Support for changeable cursor shape
62
 * by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>, August 1997
63
 *
64
 * Ported to i386 and con_scrolldelta fixed
65
 * by Emmanuel Marty <core@ggi-project.org>, April 1998
66
 *
67
 * Resurrected character buffers in videoram plus lots of other trickery
68
 * by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
69
 *
70
 * Removed old-style timers, introduced console_timer, made timer
71
 * deletion SMP-safe.  17Jun00, Andrew Morton <andrewm@uow.edu.au>
72
 *
73
 * Removed console_lock, enabled interrupts across all console operations
74
 * 13 March 2001, Andrew Morton
75
 */
76
 
77
#include <linux/module.h>
78
#include <linux/sched.h>
79
#include <linux/tty.h>
80
#include <linux/tty_flip.h>
81
#include <linux/kernel.h>
82
#include <linux/string.h>
83
#include <linux/errno.h>
84
#include <linux/kd.h>
85
#include <linux/slab.h>
86
#include <linux/major.h>
87
#include <linux/mm.h>
88
#include <linux/console.h>
89
#include <linux/init.h>
90
#include <linux/devfs_fs_kernel.h>
91
#include <linux/vt_kern.h>
92
#include <linux/selection.h>
93
#include <linux/console_struct.h>
94
#include <linux/kbd_kern.h>
95
#include <linux/consolemap.h>
96
#include <linux/timer.h>
97
#include <linux/interrupt.h>
98
#include <linux/config.h>
99
#include <linux/version.h>
100
#include <linux/tqueue.h>
101
#include <linux/bootmem.h>
102
#include <linux/pm.h>
103
#include <linux/smp_lock.h>
104
 
105
#include <asm/io.h>
106
#include <asm/system.h>
107
#include <asm/uaccess.h>
108
#include <asm/bitops.h>
109
 
110
#include "console_macros.h"
111
 
112
 
113
const struct consw *conswitchp;
114
 
115
static void __console_callback(void);
116
 
117
/* A bitmap for codes <32. A bit of 1 indicates that the code
118
 * corresponding to that bit number invokes some special action
119
 * (such as cursor movement) and should not be displayed as a
120
 * glyph unless the disp_ctrl mode is explicitly enabled.
121
 */
122
#define CTRL_ACTION 0x0d00ff81
123
#define CTRL_ALWAYS 0x0800f501  /* Cannot be overridden by disp_ctrl */
124
 
125
/*
126
 * Here is the default bell parameters: 750HZ, 1/8th of a second
127
 */
128
#define DEFAULT_BELL_PITCH      750
129
#define DEFAULT_BELL_DURATION   (HZ/8)
130
 
131
extern void vcs_make_devfs (unsigned int index, int unregister);
132
 
133
#ifndef MIN
134
#define MIN(a,b)        ((a) < (b) ? (a) : (b))
135
#endif
136
 
137
static struct tty_struct *console_table[MAX_NR_CONSOLES];
138
static struct termios *console_termios[MAX_NR_CONSOLES];
139
static struct termios *console_termios_locked[MAX_NR_CONSOLES];
140
struct vc vc_cons [MAX_NR_CONSOLES];
141
 
142
#ifndef VT_SINGLE_DRIVER
143
static const struct consw *con_driver_map[MAX_NR_CONSOLES];
144
#endif
145
 
146
static int con_open(struct tty_struct *, struct file *);
147
static void vc_init(unsigned int console, unsigned int rows,
148
                    unsigned int cols, int do_clear);
149
static void blank_screen(unsigned long dummy);
150
static void gotoxy(int currcons, int new_x, int new_y);
151
static void save_cur(int currcons);
152
static void reset_terminal(int currcons, int do_clear);
153
static void con_flush_chars(struct tty_struct *tty);
154
static void set_vesa_blanking(unsigned long arg);
155
static void set_cursor(int currcons);
156
static void hide_cursor(int currcons);
157
static void unblank_screen_t(unsigned long dummy);
158
static void console_callback(void *ignored);
159
 
160
static int printable;           /* Is console ready for printing? */
161
 
162
int do_poke_blanked_console;
163
int console_blanked;
164
 
165
static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
166
static int blankinterval = 10*60*HZ;
167
static int vesa_off_interval;
168
 
169
static struct tq_struct console_callback_tq = {
170
        routine: console_callback,
171
};
172
 
173
/*
174
 * fg_console is the current virtual console,
175
 * last_console is the last used one,
176
 * want_console is the console we want to switch to,
177
 * kmsg_redirect is the console for kernel messages,
178
 */
179
int fg_console;
180
int last_console;
181
int want_console = -1;
182
int kmsg_redirect;
183
 
184
/*
185
 * For each existing display, we have a pointer to console currently visible
186
 * on that display, allowing consoles other than fg_console to be refreshed
187
 * appropriately. Unless the low-level driver supplies its own display_fg
188
 * variable, we use this one for the "master display".
189
 */
190
static struct vc_data *master_display_fg;
191
 
192
/*
193
 * Unfortunately, we need to delay tty echo when we're currently writing to the
194
 * console since the code is (and always was) not re-entrant, so we schedule
195
 * all flip requests to process context with schedule-task() and run it from
196
 * console_callback().
197
 */
198
 
199
/*
200
 * For the same reason, we defer scrollback to the console callback.
201
 */
202
static int scrollback_delta;
203
 
204
/*
205
 * Hook so that the power management routines can (un)blank
206
 * the console on our behalf.
207
 */
208
int (*console_blank_hook)(int);
209
 
210
static struct timer_list console_timer;
211
 
212
/*
213
 *      Low-Level Functions
214
 */
215
 
216
#define IS_FG (currcons == fg_console)
217
#define IS_VISIBLE CON_IS_VISIBLE(vc_cons[currcons].d)
218
 
219
#ifdef VT_BUF_VRAM_ONLY
220
#define DO_UPDATE 0
221
#else
222
#define DO_UPDATE IS_VISIBLE
223
#endif
224
 
225
static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data);
226
static struct pm_dev *pm_con;
227
 
228
static inline unsigned short *screenpos(int currcons, int offset, int viewed)
229
{
230
        unsigned short *p;
231
 
232
        if (!viewed)
233
                p = (unsigned short *)(origin + offset);
234
        else if (!sw->con_screen_pos)
235
                p = (unsigned short *)(visible_origin + offset);
236
        else
237
                p = sw->con_screen_pos(vc_cons[currcons].d, offset);
238
        return p;
239
}
240
 
241
static inline void scrolldelta(int lines)
242
{
243
        scrollback_delta += lines;
244
        schedule_console_callback();
245
}
246
 
247
extern int machine_paniced;
248
 
249
void schedule_console_callback(void)
250
{
251
        /* Don't care about locking after panic - but I want to switch the console
252
           NOW */
253
        if (machine_paniced)
254
                __console_callback();
255
        else
256
                schedule_task(&console_callback_tq);
257
}
258
 
259
static void scrup(int currcons, unsigned int t, unsigned int b, int nr)
260
{
261
        unsigned short *d, *s;
262
 
263
        if (t+nr >= b)
264
                nr = b - t - 1;
265
        if (b > video_num_lines || t >= b || nr < 1)
266
                return;
267
        if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_UP, nr))
268
                return;
269
        d = (unsigned short *) (origin+video_size_row*t);
270
        s = (unsigned short *) (origin+video_size_row*(t+nr));
271
        scr_memcpyw(d, s, (b-t-nr) * video_size_row);
272
        scr_memsetw(d + (b-t-nr) * video_num_columns, video_erase_char, video_size_row*nr);
273
}
274
 
275
static void
276
scrdown(int currcons, unsigned int t, unsigned int b, int nr)
277
{
278
        unsigned short *s;
279
        unsigned int step;
280
 
281
        if (t+nr >= b)
282
                nr = b - t - 1;
283
        if (b > video_num_lines || t >= b || nr < 1)
284
                return;
285
        if (IS_VISIBLE && sw->con_scroll(vc_cons[currcons].d, t, b, SM_DOWN, nr))
286
                return;
287
        s = (unsigned short *) (origin+video_size_row*t);
288
        step = video_num_columns * nr;
289
        scr_memmovew(s + step, s, (b-t-nr)*video_size_row);
290
        scr_memsetw(s, video_erase_char, 2*step);
291
}
292
 
293
static void do_update_region(int currcons, unsigned long start, int count)
294
{
295
#ifndef VT_BUF_VRAM_ONLY
296
        unsigned int xx, yy, offset;
297
        u16 *p;
298
 
299
        p = (u16 *) start;
300
        if (!sw->con_getxy) {
301
                offset = (start - origin) / 2;
302
                xx = offset % video_num_columns;
303
                yy = offset / video_num_columns;
304
        } else {
305
                int nxx, nyy;
306
                start = sw->con_getxy(vc_cons[currcons].d, start, &nxx, &nyy);
307
                xx = nxx; yy = nyy;
308
        }
309
        for(;;) {
310
                u16 attrib = scr_readw(p) & 0xff00;
311
                int startx = xx;
312
                u16 *q = p;
313
                while (xx < video_num_columns && count) {
314
                        if (attrib != (scr_readw(p) & 0xff00)) {
315
                                if (p > q)
316
                                        sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
317
                                startx = xx;
318
                                q = p;
319
                                attrib = scr_readw(p) & 0xff00;
320
                        }
321
                        p++;
322
                        xx++;
323
                        count--;
324
                }
325
                if (p > q)
326
                        sw->con_putcs(vc_cons[currcons].d, q, p-q, yy, startx);
327
                if (!count)
328
                        break;
329
                xx = 0;
330
                yy++;
331
                if (sw->con_getxy) {
332
                        p = (u16 *)start;
333
                        start = sw->con_getxy(vc_cons[currcons].d, start, NULL, NULL);
334
                }
335
        }
336
#endif
337
}
338
 
339
void update_region(int currcons, unsigned long start, int count)
340
{
341
        if (DO_UPDATE) {
342
                hide_cursor(currcons);
343
                do_update_region(currcons, start, count);
344
                set_cursor(currcons);
345
        }
346
}
347
 
348
/* Structure of attributes is hardware-dependent */
349
 
350
static u8 build_attr(int currcons, u8 _color, u8 _intensity, u8 _blink, u8 _underline, u8 _reverse)
351
{
352
        if (sw->con_build_attr)
353
                return sw->con_build_attr(vc_cons[currcons].d, _color, _intensity, _blink, _underline, _reverse);
354
 
355
#ifndef VT_BUF_VRAM_ONLY
356
/*
357
 * ++roman: I completely changed the attribute format for monochrome
358
 * mode (!can_do_color). The formerly used MDA (monochrome display
359
 * adapter) format didn't allow the combination of certain effects.
360
 * Now the attribute is just a bit vector:
361
 *  Bit 0..1: intensity (0..2)
362
 *  Bit 2   : underline
363
 *  Bit 3   : reverse
364
 *  Bit 7   : blink
365
 */
366
        {
367
        u8 a = color;
368
        if (!can_do_color)
369
                return _intensity |
370
                       (_underline ? 4 : 0) |
371
                       (_reverse ? 8 : 0) |
372
                       (_blink ? 0x80 : 0);
373
        if (_underline)
374
                a = (a & 0xf0) | ulcolor;
375
        else if (_intensity == 0)
376
                a = (a & 0xf0) | halfcolor;
377
        if (_reverse)
378
                a = ((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77);
379
        if (_blink)
380
                a ^= 0x80;
381
        if (_intensity == 2)
382
                a ^= 0x08;
383
        if (hi_font_mask == 0x100)
384
                a <<= 1;
385
        return a;
386
        }
387
#else
388
        return 0;
389
#endif
390
}
391
 
392
static void update_attr(int currcons)
393
{
394
        attr = build_attr(currcons, color, intensity, blink, underline, reverse ^ decscnm);
395
        video_erase_char = (build_attr(currcons, color, 1, blink, 0, decscnm) << 8) | ' ';
396
}
397
 
398
/* Note: inverting the screen twice should revert to the original state */
399
 
400
void invert_screen(int currcons, int offset, int count, int viewed)
401
{
402
        unsigned short *p;
403
 
404
        count /= 2;
405
        p = screenpos(currcons, offset, viewed);
406
        if (sw->con_invert_region)
407
                sw->con_invert_region(vc_cons[currcons].d, p, count);
408
#ifndef VT_BUF_VRAM_ONLY
409
        else {
410
                u16 *q = p;
411
                int cnt = count;
412
                u16 a;
413
 
414
                if (!can_do_color) {
415
                        while (cnt--) {
416
                            a = scr_readw(q);
417
                            a ^= 0x0800;
418
                            scr_writew(a, q);
419
                            q++;
420
                        }
421
                } else if (hi_font_mask == 0x100) {
422
                        while (cnt--) {
423
                                a = scr_readw(q);
424
                                a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
425
                                scr_writew(a, q);
426
                                q++;
427
                        }
428
                } else {
429
                        while (cnt--) {
430
                                a = scr_readw(q);
431
                                a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
432
                                scr_writew(a, q);
433
                                q++;
434
                        }
435
                }
436
        }
437
#endif
438
        if (DO_UPDATE)
439
                do_update_region(currcons, (unsigned long) p, count);
440
}
441
 
442
/* used by selection: complement pointer position */
443
void complement_pos(int currcons, int offset)
444
{
445
        static unsigned short *p;
446
        static unsigned short old;
447
        static unsigned short oldx, oldy;
448
 
449
        if (p) {
450
                scr_writew(old, p);
451
                if (DO_UPDATE)
452
                        sw->con_putc(vc_cons[currcons].d, old, oldy, oldx);
453
        }
454
        if (offset == -1)
455
                p = NULL;
456
        else {
457
                unsigned short new;
458
                p = screenpos(currcons, offset, 1);
459
                old = scr_readw(p);
460
                new = old ^ complement_mask;
461
                scr_writew(new, p);
462
                if (DO_UPDATE) {
463
                        oldx = (offset >> 1) % video_num_columns;
464
                        oldy = (offset >> 1) / video_num_columns;
465
                        sw->con_putc(vc_cons[currcons].d, new, oldy, oldx);
466
                }
467
        }
468
}
469
 
470
static void insert_char(int currcons, unsigned int nr)
471
{
472
        unsigned short *p, *q = (unsigned short *) pos;
473
 
474
        p = q + video_num_columns - nr - x;
475
        while (--p >= q)
476
                scr_writew(scr_readw(p), p + nr);
477
        scr_memsetw(q, video_erase_char, nr*2);
478
        need_wrap = 0;
479
        if (DO_UPDATE) {
480
                unsigned short oldattr = attr;
481
                sw->con_bmove(vc_cons[currcons].d,y,x,y,x+nr,1,
482
                              video_num_columns-x-nr);
483
                attr = video_erase_char >> 8;
484
                while (nr--)
485
                        sw->con_putc(vc_cons[currcons].d,
486
                                     video_erase_char,y,x+nr);
487
                attr = oldattr;
488
        }
489
}
490
 
491
static void delete_char(int currcons, unsigned int nr)
492
{
493
        unsigned int i = x;
494
        unsigned short *p = (unsigned short *) pos;
495
 
496
        while (++i <= video_num_columns - nr) {
497
                scr_writew(scr_readw(p+nr), p);
498
                p++;
499
        }
500
        scr_memsetw(p, video_erase_char, nr*2);
501
        need_wrap = 0;
502
        if (DO_UPDATE) {
503
                unsigned short oldattr = attr;
504
                sw->con_bmove(vc_cons[currcons].d, y, x+nr, y, x, 1,
505
                              video_num_columns-x-nr);
506
                attr = video_erase_char >> 8;
507
                while (nr--)
508
                        sw->con_putc(vc_cons[currcons].d,
509
                                     video_erase_char, y,
510
                                     video_num_columns-1-nr);
511
                attr = oldattr;
512
        }
513
}
514
 
515
static int softcursor_original;
516
 
517
static void add_softcursor(int currcons)
518
{
519
        int i = scr_readw((u16 *) pos);
520
        u32 type = cursor_type;
521
 
522
        if (! (type & 0x10)) return;
523
        if (softcursor_original != -1) return;
524
        softcursor_original = i;
525
        i |= ((type >> 8) & 0xff00 );
526
        i ^= ((type) & 0xff00 );
527
        if ((type & 0x20) && ((softcursor_original & 0x7000) == (i & 0x7000))) i ^= 0x7000;
528
        if ((type & 0x40) && ((i & 0x700) == ((i & 0x7000) >> 4))) i ^= 0x0700;
529
        scr_writew(i, (u16 *) pos);
530
        if (DO_UPDATE)
531
                sw->con_putc(vc_cons[currcons].d, i, y, x);
532
}
533
 
534
static void hide_cursor(int currcons)
535
{
536
        if (currcons == sel_cons)
537
                clear_selection();
538
        if (softcursor_original != -1) {
539
                scr_writew(softcursor_original,(u16 *) pos);
540
                if (DO_UPDATE)
541
                        sw->con_putc(vc_cons[currcons].d, softcursor_original, y, x);
542
                softcursor_original = -1;
543
        }
544
        sw->con_cursor(vc_cons[currcons].d,CM_ERASE);
545
}
546
 
547
static void set_cursor(int currcons)
548
{
549
    if (!IS_FG || console_blanked || vcmode == KD_GRAPHICS)
550
        return;
551
    if (deccm) {
552
        if (currcons == sel_cons)
553
                clear_selection();
554
        add_softcursor(currcons);
555
        if ((cursor_type & 0x0f) != 1)
556
            sw->con_cursor(vc_cons[currcons].d,CM_DRAW);
557
    } else
558
        hide_cursor(currcons);
559
}
560
 
561
static void set_origin(int currcons)
562
{
563
        if (!IS_VISIBLE ||
564
            !sw->con_set_origin ||
565
            !sw->con_set_origin(vc_cons[currcons].d))
566
                origin = (unsigned long) screenbuf;
567
        visible_origin = origin;
568
        scr_end = origin + screenbuf_size;
569
        pos = origin + video_size_row*y + 2*x;
570
}
571
 
572
static inline void save_screen(int currcons)
573
{
574
        if (sw->con_save_screen)
575
                sw->con_save_screen(vc_cons[currcons].d);
576
}
577
 
578
/*
579
 *      Redrawing of screen
580
 */
581
 
582
void redraw_screen(int new_console, int is_switch)
583
{
584
        int redraw = 1;
585
        int currcons, old_console;
586
 
587
        if (!vc_cons_allocated(new_console)) {
588
                /* strange ... */
589
                /* printk("redraw_screen: tty %d not allocated ??\n", new_console+1); */
590
                return;
591
        }
592
 
593
        if (is_switch) {
594
                currcons = fg_console;
595
                hide_cursor(currcons);
596
                if (fg_console != new_console) {
597
                        struct vc_data **display = vc_cons[new_console].d->vc_display_fg;
598
                        old_console = (*display) ? (*display)->vc_num : fg_console;
599
                        *display = vc_cons[new_console].d;
600
                        fg_console = new_console;
601
                        currcons = old_console;
602
                        if (!IS_VISIBLE) {
603
                                save_screen(currcons);
604
                                set_origin(currcons);
605
                        }
606
                        currcons = new_console;
607
                        if (old_console == new_console)
608
                                redraw = 0;
609
                }
610
        } else {
611
                currcons = new_console;
612
                hide_cursor(currcons);
613
        }
614
 
615
        if (redraw) {
616
                int update;
617
                set_origin(currcons);
618
                update = sw->con_switch(vc_cons[currcons].d);
619
                set_palette(currcons);
620
                if (update && vcmode != KD_GRAPHICS)
621
                        do_update_region(currcons, origin, screenbuf_size/2);
622
        }
623
        set_cursor(currcons);
624
        if (is_switch) {
625
                set_leds();
626
                compute_shiftstate();
627
        }
628
}
629
 
630
/*
631
 *      Allocation, freeing and resizing of VTs.
632
 */
633
 
634
int vc_cons_allocated(unsigned int i)
635
{
636
        return (i < MAX_NR_CONSOLES && vc_cons[i].d);
637
}
638
 
639
static void visual_init(int currcons, int init)
640
{
641
    /* ++Geert: sw->con_init determines console size */
642
    sw = conswitchp;
643
#ifndef VT_SINGLE_DRIVER
644
    if (con_driver_map[currcons])
645
        sw = con_driver_map[currcons];
646
#endif
647
    cons_num = currcons;
648
    display_fg = &master_display_fg;
649
    vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir;
650
    vc_cons[currcons].d->vc_uni_pagedir = 0;
651
    hi_font_mask = 0;
652
    complement_mask = 0;
653
    can_do_color = 0;
654
    sw->con_init(vc_cons[currcons].d, init);
655
    if (!complement_mask)
656
        complement_mask = can_do_color ? 0x7700 : 0x0800;
657
    s_complement_mask = complement_mask;
658
    video_size_row = video_num_columns<<1;
659
    screenbuf_size = video_num_lines*video_size_row;
660
}
661
 
662
int vc_allocate(unsigned int currcons)  /* return 0 on success */
663
{
664
        if (currcons >= MAX_NR_CONSOLES)
665
                return -ENXIO;
666
        if (!vc_cons[currcons].d) {
667
            long p, q;
668
 
669
            /* prevent users from taking too much memory */
670
            if (currcons >= MAX_NR_USER_CONSOLES && !capable(CAP_SYS_RESOURCE))
671
              return -EPERM;
672
 
673
            /* due to the granularity of kmalloc, we waste some memory here */
674
            /* the alloc is done in two steps, to optimize the common situation
675
               of a 25x80 console (structsize=216, screenbuf_size=4000) */
676
            /* although the numbers above are not valid since long ago, the
677
               point is still up-to-date and the comment still has its value
678
               even if only as a historical artifact.  --mj, July 1998 */
679
            p = (long) kmalloc(structsize, GFP_KERNEL);
680
            if (!p)
681
                return -ENOMEM;
682
            memset((void *)p, 0, structsize);
683
            vc_cons[currcons].d = (struct vc_data *)p;
684
            vt_cons[currcons] = (struct vt_struct *)(p+sizeof(struct vc_data));
685
            visual_init(currcons, 1);
686
            if (!*vc_cons[currcons].d->vc_uni_pagedir_loc)
687
                con_set_default_unimap(currcons);
688
            q = (long)kmalloc(screenbuf_size, GFP_KERNEL);
689
            if (!q) {
690
                kfree((char *) p);
691
                vc_cons[currcons].d = NULL;
692
                vt_cons[currcons] = NULL;
693
                return -ENOMEM;
694
            }
695
            screenbuf = (unsigned short *) q;
696
            kmalloced = 1;
697
            vc_init(currcons, video_num_lines, video_num_columns, 1);
698
 
699
            if (!pm_con) {
700
                    pm_con = pm_register(PM_SYS_DEV,
701
                                         PM_SYS_VGA,
702
                                         pm_con_request);
703
            }
704
        }
705
        return 0;
706
}
707
 
708
/*
709
 * Change # of rows and columns (0 means unchanged/the size of fg_console)
710
 * [this is to be used together with some user program
711
 * like resize that changes the hardware videomode]
712
 */
713
int vc_resize(unsigned int lines, unsigned int cols,
714
              unsigned int first, unsigned int last)
715
{
716
        unsigned int cc, ll, ss, sr, todo = 0;
717
        unsigned int currcons = fg_console, i;
718
        unsigned short *newscreens[MAX_NR_CONSOLES];
719
 
720
        cc = (cols ? cols : video_num_columns);
721
        ll = (lines ? lines : video_num_lines);
722
        sr = cc << 1;
723
        ss = sr * ll;
724
 
725
        for (currcons = first; currcons <= last; currcons++) {
726
                if (!vc_cons_allocated(currcons) ||
727
                    (cc == video_num_columns && ll == video_num_lines))
728
                        newscreens[currcons] = NULL;
729
                else {
730
                        unsigned short *p = (unsigned short *) kmalloc(ss, GFP_USER);
731
                        if (!p) {
732
                                for (i = first; i < currcons; i++)
733
                                        if (newscreens[i])
734
                                                kfree(newscreens[i]);
735
                                return -ENOMEM;
736
                        }
737
                        newscreens[currcons] = p;
738
                        todo++;
739
                }
740
        }
741
        if (!todo)
742
                return 0;
743
 
744
        for (currcons = first; currcons <= last; currcons++) {
745
                unsigned int occ, oll, oss, osr;
746
                unsigned long ol, nl, nlend, rlth, rrem;
747
                if (!newscreens[currcons] || !vc_cons_allocated(currcons))
748
                        continue;
749
 
750
                oll = video_num_lines;
751
                occ = video_num_columns;
752
                osr = video_size_row;
753
                oss = screenbuf_size;
754
 
755
                video_num_lines = ll;
756
                video_num_columns = cc;
757
                video_size_row = sr;
758
                screenbuf_size = ss;
759
 
760
                rlth = MIN(osr, sr);
761
                rrem = sr - rlth;
762
                ol = origin;
763
                nl = (long) newscreens[currcons];
764
                nlend = nl + ss;
765
                if (ll < oll)
766
                        ol += (oll - ll) * osr;
767
 
768
                update_attr(currcons);
769
 
770
                while (ol < scr_end) {
771
                        scr_memcpyw((unsigned short *) nl, (unsigned short *) ol, rlth);
772
                        if (rrem)
773
                                scr_memsetw((void *)(nl + rlth), video_erase_char, rrem);
774
                        ol += osr;
775
                        nl += sr;
776
                }
777
                if (nlend > nl)
778
                        scr_memsetw((void *) nl, video_erase_char, nlend - nl);
779
                if (kmalloced)
780
                        kfree(screenbuf);
781
                screenbuf = newscreens[currcons];
782
                kmalloced = 1;
783
                screenbuf_size = ss;
784
                set_origin(currcons);
785
 
786
                /* do part of a reset_terminal() */
787
                top = 0;
788
                bottom = video_num_lines;
789
                gotoxy(currcons, x, y);
790
                save_cur(currcons);
791
 
792
                if (console_table[currcons]) {
793
                        struct winsize ws, *cws = &console_table[currcons]->winsize;
794
                        memset(&ws, 0, sizeof(ws));
795
                        ws.ws_row = video_num_lines;
796
                        ws.ws_col = video_num_columns;
797
                        if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
798
                            console_table[currcons]->pgrp > 0)
799
                                kill_pg(console_table[currcons]->pgrp, SIGWINCH, 1);
800
                        *cws = ws;
801
                }
802
 
803
                if (IS_VISIBLE)
804
                        update_screen(currcons);
805
        }
806
 
807
        return 0;
808
}
809
 
810
 
811
void vc_disallocate(unsigned int currcons)
812
{
813
        acquire_console_sem();
814
        if (vc_cons_allocated(currcons)) {
815
            sw->con_deinit(vc_cons[currcons].d);
816
            if (kmalloced)
817
                kfree(screenbuf);
818
            if (currcons >= MIN_NR_CONSOLES)
819
                kfree(vc_cons[currcons].d);
820
            vc_cons[currcons].d = NULL;
821
        }
822
        release_console_sem();
823
}
824
 
825
/*
826
 *      VT102 emulator
827
 */
828
 
829
#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x)
830
#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x)
831
#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x)
832
 
833
#define decarm          VC_REPEAT
834
#define decckm          VC_CKMODE
835
#define kbdapplic       VC_APPLIC
836
#define lnm             VC_CRLF
837
 
838
/*
839
 * this is what the terminal answers to a ESC-Z or csi0c query.
840
 */
841
#define VT100ID "\033[?1;2c"
842
#define VT102ID "\033[?6c"
843
 
844
unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
845
                                       8,12,10,14, 9,13,11,15 };
846
 
847
/* the default colour table, for VGA+ colour systems */
848
int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
849
    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
850
int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
851
    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
852
int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
853
    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
854
 
855
/*
856
 * gotoxy() must verify all boundaries, because the arguments
857
 * might also be negative. If the given position is out of
858
 * bounds, the cursor is placed at the nearest margin.
859
 */
860
static void gotoxy(int currcons, int new_x, int new_y)
861
{
862
        int min_y, max_y;
863
 
864
        if (new_x < 0)
865
                x = 0;
866
        else
867
                if (new_x >= video_num_columns)
868
                        x = video_num_columns - 1;
869
                else
870
                        x = new_x;
871
        if (decom) {
872
                min_y = top;
873
                max_y = bottom;
874
        } else {
875
                min_y = 0;
876
                max_y = video_num_lines;
877
        }
878
        if (new_y < min_y)
879
                y = min_y;
880
        else if (new_y >= max_y)
881
                y = max_y - 1;
882
        else
883
                y = new_y;
884
        pos = origin + y*video_size_row + (x<<1);
885
        need_wrap = 0;
886
}
887
 
888
/* for absolute user moves, when decom is set */
889
static void gotoxay(int currcons, int new_x, int new_y)
890
{
891
        gotoxy(currcons, new_x, decom ? (top+new_y) : new_y);
892
}
893
 
894
void scrollback(int lines)
895
{
896
        int currcons = fg_console;
897
 
898
        if (!lines)
899
                lines = video_num_lines/2;
900
        scrolldelta(-lines);
901
}
902
 
903
void scrollfront(int lines)
904
{
905
        int currcons = fg_console;
906
 
907
        if (!lines)
908
                lines = video_num_lines/2;
909
        scrolldelta(lines);
910
}
911
 
912
static void lf(int currcons)
913
{
914
        /* don't scroll if above bottom of scrolling region, or
915
         * if below scrolling region
916
         */
917
        if (y+1 == bottom)
918
                scrup(currcons,top,bottom,1);
919
        else if (y < video_num_lines-1) {
920
                y++;
921
                pos += video_size_row;
922
        }
923
        need_wrap = 0;
924
}
925
 
926
static void ri(int currcons)
927
{
928
        /* don't scroll if below top of scrolling region, or
929
         * if above scrolling region
930
         */
931
        if (y == top)
932
                scrdown(currcons,top,bottom,1);
933
        else if (y > 0) {
934
                y--;
935
                pos -= video_size_row;
936
        }
937
        need_wrap = 0;
938
}
939
 
940
static inline void cr(int currcons)
941
{
942
        pos -= x<<1;
943
        need_wrap = x = 0;
944
}
945
 
946
static inline void bs(int currcons)
947
{
948
        if (x) {
949
                pos -= 2;
950
                x--;
951
                need_wrap = 0;
952
        }
953
}
954
 
955
static inline void del(int currcons)
956
{
957
        /* ignored */
958
}
959
 
960
static void csi_J(int currcons, int vpar)
961
{
962
        unsigned int count;
963
        unsigned short * start;
964
 
965
        switch (vpar) {
966
                case 0:  /* erase from cursor to end of display */
967
                        count = (scr_end-pos)>>1;
968
                        start = (unsigned short *) pos;
969
                        if (DO_UPDATE) {
970
                                /* do in two stages */
971
                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
972
                                              video_num_columns-x);
973
                                sw->con_clear(vc_cons[currcons].d, y+1, 0,
974
                                              video_num_lines-y-1,
975
                                              video_num_columns);
976
                        }
977
                        break;
978
                case 1: /* erase from start to cursor */
979
                        count = ((pos-origin)>>1)+1;
980
                        start = (unsigned short *) origin;
981
                        if (DO_UPDATE) {
982
                                /* do in two stages */
983
                                sw->con_clear(vc_cons[currcons].d, 0, 0, y,
984
                                              video_num_columns);
985
                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
986
                                              x + 1);
987
                        }
988
                        break;
989
                case 2: /* erase whole display */
990
                        count = video_num_columns * video_num_lines;
991
                        start = (unsigned short *) origin;
992
                        if (DO_UPDATE)
993
                                sw->con_clear(vc_cons[currcons].d, 0, 0,
994
                                              video_num_lines,
995
                                              video_num_columns);
996
                        break;
997
                default:
998
                        return;
999
        }
1000
        scr_memsetw(start, video_erase_char, 2*count);
1001
        need_wrap = 0;
1002
}
1003
 
1004
static void csi_K(int currcons, int vpar)
1005
{
1006
        unsigned int count;
1007
        unsigned short * start;
1008
 
1009
        switch (vpar) {
1010
                case 0:  /* erase from cursor to end of line */
1011
                        count = video_num_columns-x;
1012
                        start = (unsigned short *) pos;
1013
                        if (DO_UPDATE)
1014
                                sw->con_clear(vc_cons[currcons].d, y, x, 1,
1015
                                              video_num_columns-x);
1016
                        break;
1017
                case 1: /* erase from start of line to cursor */
1018
                        start = (unsigned short *) (pos - (x<<1));
1019
                        count = x+1;
1020
                        if (DO_UPDATE)
1021
                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1022
                                              x + 1);
1023
                        break;
1024
                case 2: /* erase whole line */
1025
                        start = (unsigned short *) (pos - (x<<1));
1026
                        count = video_num_columns;
1027
                        if (DO_UPDATE)
1028
                                sw->con_clear(vc_cons[currcons].d, y, 0, 1,
1029
                                              video_num_columns);
1030
                        break;
1031
                default:
1032
                        return;
1033
        }
1034
        scr_memsetw(start, video_erase_char, 2 * count);
1035
        need_wrap = 0;
1036
}
1037
 
1038
static void csi_X(int currcons, int vpar) /* erase the following vpar positions */
1039
{                                         /* not vt100? */
1040
        int count;
1041
 
1042
        if (!vpar)
1043
                vpar++;
1044
        count = (vpar > video_num_columns-x) ? (video_num_columns-x) : vpar;
1045
 
1046
        scr_memsetw((unsigned short *) pos, video_erase_char, 2 * count);
1047
        if (DO_UPDATE)
1048
                sw->con_clear(vc_cons[currcons].d, y, x, 1, count);
1049
        need_wrap = 0;
1050
}
1051
 
1052
static void default_attr(int currcons)
1053
{
1054
        intensity = 1;
1055
        underline = 0;
1056
        reverse = 0;
1057
        blink = 0;
1058
        color = def_color;
1059
}
1060
 
1061
/* console_sem is held */
1062
static void csi_m(int currcons)
1063
{
1064
        int i;
1065
 
1066
        for (i=0;i<=npar;i++)
1067
                switch (par[i]) {
1068
                        case 0:  /* all attributes off */
1069
                                default_attr(currcons);
1070
                                break;
1071
                        case 1:
1072
                                intensity = 2;
1073
                                break;
1074
                        case 2:
1075
                                intensity = 0;
1076
                                break;
1077
                        case 4:
1078
                                underline = 1;
1079
                                break;
1080
                        case 5:
1081
                                blink = 1;
1082
                                break;
1083
                        case 7:
1084
                                reverse = 1;
1085
                                break;
1086
                        case 10: /* ANSI X3.64-1979 (SCO-ish?)
1087
                                  * Select primary font, don't display
1088
                                  * control chars if defined, don't set
1089
                                  * bit 8 on output.
1090
                                  */
1091
                                translate = set_translate(charset == 0
1092
                                                ? G0_charset
1093
                                                : G1_charset,currcons);
1094
                                disp_ctrl = 0;
1095
                                toggle_meta = 0;
1096
                                break;
1097
                        case 11: /* ANSI X3.64-1979 (SCO-ish?)
1098
                                  * Select first alternate font, lets
1099
                                  * chars < 32 be displayed as ROM chars.
1100
                                  */
1101
                                translate = set_translate(IBMPC_MAP,currcons);
1102
                                disp_ctrl = 1;
1103
                                toggle_meta = 0;
1104
                                break;
1105
                        case 12: /* ANSI X3.64-1979 (SCO-ish?)
1106
                                  * Select second alternate font, toggle
1107
                                  * high bit before displaying as ROM char.
1108
                                  */
1109
                                translate = set_translate(IBMPC_MAP,currcons);
1110
                                disp_ctrl = 1;
1111
                                toggle_meta = 1;
1112
                                break;
1113
                        case 21:
1114
                        case 22:
1115
                                intensity = 1;
1116
                                break;
1117
                        case 24:
1118
                                underline = 0;
1119
                                break;
1120
                        case 25:
1121
                                blink = 0;
1122
                                break;
1123
                        case 27:
1124
                                reverse = 0;
1125
                                break;
1126
                        case 38: /* ANSI X3.64-1979 (SCO-ish?)
1127
                                  * Enables underscore, white foreground
1128
                                  * with white underscore (Linux - use
1129
                                  * default foreground).
1130
                                  */
1131
                                color = (def_color & 0x0f) | background;
1132
                                underline = 1;
1133
                                break;
1134
                        case 39: /* ANSI X3.64-1979 (SCO-ish?)
1135
                                  * Disable underline option.
1136
                                  * Reset colour to default? It did this
1137
                                  * before...
1138
                                  */
1139
                                color = (def_color & 0x0f) | background;
1140
                                underline = 0;
1141
                                break;
1142
                        case 49:
1143
                                color = (def_color & 0xf0) | foreground;
1144
                                break;
1145
                        default:
1146
                                if (par[i] >= 30 && par[i] <= 37)
1147
                                        color = color_table[par[i]-30]
1148
                                                | background;
1149
                                else if (par[i] >= 40 && par[i] <= 47)
1150
                                        color = (color_table[par[i]-40]<<4)
1151
                                                | foreground;
1152
                                break;
1153
                }
1154
        update_attr(currcons);
1155
}
1156
 
1157
static void respond_string(const char * p, struct tty_struct * tty)
1158
{
1159
        while (*p) {
1160
                tty_insert_flip_char(tty, *p, 0);
1161
                p++;
1162
        }
1163
        con_schedule_flip(tty);
1164
}
1165
 
1166
static void cursor_report(int currcons, struct tty_struct * tty)
1167
{
1168
        char buf[40];
1169
 
1170
        sprintf(buf, "\033[%d;%dR", y + (decom ? top+1 : 1), x+1);
1171
        respond_string(buf, tty);
1172
}
1173
 
1174
static inline void status_report(struct tty_struct * tty)
1175
{
1176
        respond_string("\033[0n", tty); /* Terminal ok */
1177
}
1178
 
1179
static inline void respond_ID(struct tty_struct * tty)
1180
{
1181
        respond_string(VT102ID, tty);
1182
}
1183
 
1184
void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry)
1185
{
1186
        char buf[8];
1187
 
1188
        sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt), (char)('!' + mrx),
1189
                (char)('!' + mry));
1190
        respond_string(buf, tty);
1191
}
1192
 
1193
/* invoked via ioctl(TIOCLINUX) and through set_selection */
1194
int mouse_reporting(void)
1195
{
1196
        int currcons = fg_console;
1197
 
1198
        return report_mouse;
1199
}
1200
 
1201
/* console_sem is held */
1202
static void set_mode(int currcons, int on_off)
1203
{
1204
        int i;
1205
 
1206
        for (i=0; i<=npar; i++)
1207
                if (ques) switch(par[i]) {      /* DEC private modes set/reset */
1208
                        case 1:                 /* Cursor keys send ^[Ox/^[[x */
1209
                                if (on_off)
1210
                                        set_kbd(decckm);
1211
                                else
1212
                                        clr_kbd(decckm);
1213
                                break;
1214
                        case 3: /* 80/132 mode switch unimplemented */
1215
                                deccolm = on_off;
1216
#if 0
1217
                                (void) vc_resize(video_num_lines, deccolm ? 132 : 80);
1218
                                /* this alone does not suffice; some user mode
1219
                                   utility has to change the hardware regs */
1220
#endif
1221
                                break;
1222
                        case 5:                 /* Inverted screen on/off */
1223
                                if (decscnm != on_off) {
1224
                                        decscnm = on_off;
1225
                                        invert_screen(currcons, 0, screenbuf_size, 0);
1226
                                        update_attr(currcons);
1227
                                }
1228
                                break;
1229
                        case 6:                 /* Origin relative/absolute */
1230
                                decom = on_off;
1231
                                gotoxay(currcons,0,0);
1232
                                break;
1233
                        case 7:                 /* Autowrap on/off */
1234
                                decawm = on_off;
1235
                                break;
1236
                        case 8:                 /* Autorepeat on/off */
1237
                                if (on_off)
1238
                                        set_kbd(decarm);
1239
                                else
1240
                                        clr_kbd(decarm);
1241
                                break;
1242
                        case 9:
1243
                                report_mouse = on_off ? 1 : 0;
1244
                                break;
1245
                        case 25:                /* Cursor on/off */
1246
                                deccm = on_off;
1247
                                break;
1248
                        case 1000:
1249
                                report_mouse = on_off ? 2 : 0;
1250
                                break;
1251
                } else switch(par[i]) {         /* ANSI modes set/reset */
1252
                        case 3:                 /* Monitor (display ctrls) */
1253
                                disp_ctrl = on_off;
1254
                                break;
1255
                        case 4:                 /* Insert Mode on/off */
1256
                                decim = on_off;
1257
                                break;
1258
                        case 20:                /* Lf, Enter == CrLf/Lf */
1259
                                if (on_off)
1260
                                        set_kbd(lnm);
1261
                                else
1262
                                        clr_kbd(lnm);
1263
                                break;
1264
                }
1265
}
1266
 
1267
/* console_sem is held */
1268
static void setterm_command(int currcons)
1269
{
1270
        switch(par[0]) {
1271
                case 1: /* set color for underline mode */
1272
                        if (can_do_color && par[1] < 16) {
1273
                                ulcolor = color_table[par[1]];
1274
                                if (underline)
1275
                                        update_attr(currcons);
1276
                        }
1277
                        break;
1278
                case 2: /* set color for half intensity mode */
1279
                        if (can_do_color && par[1] < 16) {
1280
                                halfcolor = color_table[par[1]];
1281
                                if (intensity == 0)
1282
                                        update_attr(currcons);
1283
                        }
1284
                        break;
1285
                case 8: /* store colors as defaults */
1286
                        def_color = attr;
1287
                        if (hi_font_mask == 0x100)
1288
                                def_color >>= 1;
1289
                        default_attr(currcons);
1290
                        update_attr(currcons);
1291
                        break;
1292
                case 9: /* set blanking interval */
1293
                        blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1294
                        poke_blanked_console();
1295
                        break;
1296
                case 10: /* set bell frequency in Hz */
1297
                        if (npar >= 1)
1298
                                bell_pitch = par[1];
1299
                        else
1300
                                bell_pitch = DEFAULT_BELL_PITCH;
1301
                        break;
1302
                case 11: /* set bell duration in msec */
1303
                        if (npar >= 1)
1304
                                bell_duration = (par[1] < 2000) ?
1305
                                        par[1]*HZ/1000 : 0;
1306
                        else
1307
                                bell_duration = DEFAULT_BELL_DURATION;
1308
                        break;
1309
                case 12: /* bring specified console to the front */
1310
                        if (par[1] >= 1 && vc_cons_allocated(par[1]-1))
1311
                                set_console(par[1] - 1);
1312
                        break;
1313
                case 13: /* unblank the screen */
1314
                        poke_blanked_console();
1315
                        break;
1316
                case 14: /* set vesa powerdown interval */
1317
                        vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ;
1318
                        break;
1319
        }
1320
}
1321
 
1322
/* console_sem is held */
1323
static void csi_at(int currcons, unsigned int nr)
1324
{
1325
        if (nr > video_num_columns - x)
1326
                nr = video_num_columns - x;
1327
        else if (!nr)
1328
                nr = 1;
1329
        insert_char(currcons, nr);
1330
}
1331
 
1332
/* console_sem is held */
1333
static void csi_L(int currcons, unsigned int nr)
1334
{
1335
        if (nr > video_num_lines - y)
1336
                nr = video_num_lines - y;
1337
        else if (!nr)
1338
                nr = 1;
1339
        scrdown(currcons,y,bottom,nr);
1340
        need_wrap = 0;
1341
}
1342
 
1343
/* console_sem is held */
1344
static void csi_P(int currcons, unsigned int nr)
1345
{
1346
        if (nr > video_num_columns - x)
1347
                nr = video_num_columns - x;
1348
        else if (!nr)
1349
                nr = 1;
1350
        delete_char(currcons, nr);
1351
}
1352
 
1353
/* console_sem is held */
1354
static void csi_M(int currcons, unsigned int nr)
1355
{
1356
        if (nr > video_num_lines - y)
1357
                nr = video_num_lines - y;
1358
        else if (!nr)
1359
                nr=1;
1360
        scrup(currcons,y,bottom,nr);
1361
        need_wrap = 0;
1362
}
1363
 
1364
/* console_sem is held (except via vc_init->reset_terminal */
1365
static void save_cur(int currcons)
1366
{
1367
        saved_x         = x;
1368
        saved_y         = y;
1369
        s_intensity     = intensity;
1370
        s_underline     = underline;
1371
        s_blink         = blink;
1372
        s_reverse       = reverse;
1373
        s_charset       = charset;
1374
        s_color         = color;
1375
        saved_G0        = G0_charset;
1376
        saved_G1        = G1_charset;
1377
}
1378
 
1379
/* console_sem is held */
1380
static void restore_cur(int currcons)
1381
{
1382
        gotoxy(currcons,saved_x,saved_y);
1383
        intensity       = s_intensity;
1384
        underline       = s_underline;
1385
        blink           = s_blink;
1386
        reverse         = s_reverse;
1387
        charset         = s_charset;
1388
        color           = s_color;
1389
        G0_charset      = saved_G0;
1390
        G1_charset      = saved_G1;
1391
        translate       = set_translate(charset ? G1_charset : G0_charset,currcons);
1392
        update_attr(currcons);
1393
        need_wrap = 0;
1394
}
1395
 
1396
enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
1397
        EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
1398
        ESpalette };
1399
 
1400
/* console_sem is held (except via vc_init()) */
1401
static void reset_terminal(int currcons, int do_clear)
1402
{
1403
        top             = 0;
1404
        bottom          = video_num_lines;
1405
        vc_state        = ESnormal;
1406
        ques            = 0;
1407
        translate       = set_translate(LAT1_MAP,currcons);
1408
        G0_charset      = LAT1_MAP;
1409
        G1_charset      = GRAF_MAP;
1410
        charset         = 0;
1411
        need_wrap       = 0;
1412
        report_mouse    = 0;
1413
        utf             = 0;
1414
        utf_count       = 0;
1415
 
1416
        disp_ctrl       = 0;
1417
        toggle_meta     = 0;
1418
 
1419
        decscnm         = 0;
1420
        decom           = 0;
1421
        decawm          = 1;
1422
        deccm           = 1;
1423
        decim           = 0;
1424
 
1425
        set_kbd(decarm);
1426
        clr_kbd(decckm);
1427
        clr_kbd(kbdapplic);
1428
        clr_kbd(lnm);
1429
        kbd_table[currcons].lockstate = 0;
1430
        kbd_table[currcons].slockstate = 0;
1431
        kbd_table[currcons].ledmode = LED_SHOW_FLAGS;
1432
        kbd_table[currcons].ledflagstate = kbd_table[currcons].default_ledflagstate;
1433
 
1434
        /* Only schedule the keyboard_tasklet if it is enabled. */
1435
        if(!atomic_read(&keyboard_tasklet.count))
1436
                set_leds();
1437
 
1438
        cursor_type = CUR_DEFAULT;
1439
        complement_mask = s_complement_mask;
1440
 
1441
        default_attr(currcons);
1442
        update_attr(currcons);
1443
 
1444
        tab_stop[0]      = 0x01010100;
1445
        tab_stop[1]     =
1446
        tab_stop[2]     =
1447
        tab_stop[3]     =
1448
        tab_stop[4]     = 0x01010101;
1449
 
1450
        bell_pitch = DEFAULT_BELL_PITCH;
1451
        bell_duration = DEFAULT_BELL_DURATION;
1452
 
1453
        gotoxy(currcons,0,0);
1454
        save_cur(currcons);
1455
        if (do_clear)
1456
            csi_J(currcons,2);
1457
}
1458
 
1459
/* console_sem is held */
1460
static void do_con_trol(struct tty_struct *tty, unsigned int currcons, int c)
1461
{
1462
        /*
1463
         *  Control characters can be used in the _middle_
1464
         *  of an escape sequence.
1465
         */
1466
        switch (c) {
1467
        case 0:
1468
                return;
1469
        case 7:
1470
                if (bell_duration)
1471
                        kd_mksound(bell_pitch, bell_duration);
1472
                return;
1473
        case 8:
1474
                bs(currcons);
1475
                return;
1476
        case 9:
1477
                pos -= (x << 1);
1478
                while (x < video_num_columns - 1) {
1479
                        x++;
1480
                        if (tab_stop[x >> 5] & (1 << (x & 31)))
1481
                                break;
1482
                }
1483
                pos += (x << 1);
1484
                return;
1485
        case 10: case 11: case 12:
1486
                lf(currcons);
1487
                if (!is_kbd(lnm))
1488
                        return;
1489
        case 13:
1490
                cr(currcons);
1491
                return;
1492
        case 14:
1493
                charset = 1;
1494
                translate = set_translate(G1_charset,currcons);
1495
                disp_ctrl = 1;
1496
                return;
1497
        case 15:
1498
                charset = 0;
1499
                translate = set_translate(G0_charset,currcons);
1500
                disp_ctrl = 0;
1501
                return;
1502
        case 24: case 26:
1503
                vc_state = ESnormal;
1504
                return;
1505
        case 27:
1506
                vc_state = ESesc;
1507
                return;
1508
        case 127:
1509
                del(currcons);
1510
                return;
1511
        case 128+27:
1512
                vc_state = ESsquare;
1513
                return;
1514
        }
1515
        switch(vc_state) {
1516
        case ESesc:
1517
                vc_state = ESnormal;
1518
                switch (c) {
1519
                case '[':
1520
                        vc_state = ESsquare;
1521
                        return;
1522
                case ']':
1523
                        vc_state = ESnonstd;
1524
                        return;
1525
                case '%':
1526
                        vc_state = ESpercent;
1527
                        return;
1528
                case 'E':
1529
                        cr(currcons);
1530
                        lf(currcons);
1531
                        return;
1532
                case 'M':
1533
                        ri(currcons);
1534
                        return;
1535
                case 'D':
1536
                        lf(currcons);
1537
                        return;
1538
                case 'H':
1539
                        tab_stop[x >> 5] |= (1 << (x & 31));
1540
                        return;
1541
                case 'Z':
1542
                        respond_ID(tty);
1543
                        return;
1544
                case '7':
1545
                        save_cur(currcons);
1546
                        return;
1547
                case '8':
1548
                        restore_cur(currcons);
1549
                        return;
1550
                case '(':
1551
                        vc_state = ESsetG0;
1552
                        return;
1553
                case ')':
1554
                        vc_state = ESsetG1;
1555
                        return;
1556
                case '#':
1557
                        vc_state = EShash;
1558
                        return;
1559
                case 'c':
1560
                        reset_terminal(currcons,1);
1561
                        return;
1562
                case '>':  /* Numeric keypad */
1563
                        clr_kbd(kbdapplic);
1564
                        return;
1565
                case '=':  /* Appl. keypad */
1566
                        set_kbd(kbdapplic);
1567
                        return;
1568
                }
1569
                return;
1570
        case ESnonstd:
1571
                if (c=='P') {   /* palette escape sequence */
1572
                        for (npar=0; npar<NPAR; npar++)
1573
                                par[npar] = 0 ;
1574
                        npar = 0 ;
1575
                        vc_state = ESpalette;
1576
                        return;
1577
                } else if (c=='R') {   /* reset palette */
1578
                        reset_palette(currcons);
1579
                        vc_state = ESnormal;
1580
                } else
1581
                        vc_state = ESnormal;
1582
                return;
1583
        case ESpalette:
1584
                if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
1585
                        par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
1586
                        if (npar==7) {
1587
                                int i = par[0]*3, j = 1;
1588
                                palette[i] = 16*par[j++];
1589
                                palette[i++] += par[j++];
1590
                                palette[i] = 16*par[j++];
1591
                                palette[i++] += par[j++];
1592
                                palette[i] = 16*par[j++];
1593
                                palette[i] += par[j];
1594
                                set_palette(currcons);
1595
                                vc_state = ESnormal;
1596
                        }
1597
                } else
1598
                        vc_state = ESnormal;
1599
                return;
1600
        case ESsquare:
1601
                for(npar = 0 ; npar < NPAR ; npar++)
1602
                        par[npar] = 0;
1603
                npar = 0;
1604
                vc_state = ESgetpars;
1605
                if (c == '[') { /* Function key */
1606
                        vc_state=ESfunckey;
1607
                        return;
1608
                }
1609
                ques = (c=='?');
1610
                if (ques)
1611
                        return;
1612
        case ESgetpars:
1613
                if (c==';' && npar<NPAR-1) {
1614
                        npar++;
1615
                        return;
1616
                } else if (c>='0' && c<='9') {
1617
                        par[npar] *= 10;
1618
                        par[npar] += c-'0';
1619
                        return;
1620
                } else vc_state=ESgotpars;
1621
        case ESgotpars:
1622
                vc_state = ESnormal;
1623
                switch(c) {
1624
                case 'h':
1625
                        set_mode(currcons,1);
1626
                        return;
1627
                case 'l':
1628
                        set_mode(currcons,0);
1629
                        return;
1630
                case 'c':
1631
                        if (ques) {
1632
                                if (par[0])
1633
                                        cursor_type = par[0] | (par[1]<<8) | (par[2]<<16);
1634
                                else
1635
                                        cursor_type = CUR_DEFAULT;
1636
                                return;
1637
                        }
1638
                        break;
1639
                case 'm':
1640
                        if (ques) {
1641
                                clear_selection();
1642
                                if (par[0])
1643
                                        complement_mask = par[0]<<8 | par[1];
1644
                                else
1645
                                        complement_mask = s_complement_mask;
1646
                                return;
1647
                        }
1648
                        break;
1649
                case 'n':
1650
                        if (!ques) {
1651
                                if (par[0] == 5)
1652
                                        status_report(tty);
1653
                                else if (par[0] == 6)
1654
                                        cursor_report(currcons,tty);
1655
                        }
1656
                        return;
1657
                }
1658
                if (ques) {
1659
                        ques = 0;
1660
                        return;
1661
                }
1662
                switch(c) {
1663
                case 'G': case '`':
1664
                        if (par[0]) par[0]--;
1665
                        gotoxy(currcons,par[0],y);
1666
                        return;
1667
                case 'A':
1668
                        if (!par[0]) par[0]++;
1669
                        gotoxy(currcons,x,y-par[0]);
1670
                        return;
1671
                case 'B': case 'e':
1672
                        if (!par[0]) par[0]++;
1673
                        gotoxy(currcons,x,y+par[0]);
1674
                        return;
1675
                case 'C': case 'a':
1676
                        if (!par[0]) par[0]++;
1677
                        gotoxy(currcons,x+par[0],y);
1678
                        return;
1679
                case 'D':
1680
                        if (!par[0]) par[0]++;
1681
                        gotoxy(currcons,x-par[0],y);
1682
                        return;
1683
                case 'E':
1684
                        if (!par[0]) par[0]++;
1685
                        gotoxy(currcons,0,y+par[0]);
1686
                        return;
1687
                case 'F':
1688
                        if (!par[0]) par[0]++;
1689
                        gotoxy(currcons,0,y-par[0]);
1690
                        return;
1691
                case 'd':
1692
                        if (par[0]) par[0]--;
1693
                        gotoxay(currcons,x,par[0]);
1694
                        return;
1695
                case 'H': case 'f':
1696
                        if (par[0]) par[0]--;
1697
                        if (par[1]) par[1]--;
1698
                        gotoxay(currcons,par[1],par[0]);
1699
                        return;
1700
                case 'J':
1701
                        csi_J(currcons,par[0]);
1702
                        return;
1703
                case 'K':
1704
                        csi_K(currcons,par[0]);
1705
                        return;
1706
                case 'L':
1707
                        csi_L(currcons,par[0]);
1708
                        return;
1709
                case 'M':
1710
                        csi_M(currcons,par[0]);
1711
                        return;
1712
                case 'P':
1713
                        csi_P(currcons,par[0]);
1714
                        return;
1715
                case 'c':
1716
                        if (!par[0])
1717
                                respond_ID(tty);
1718
                        return;
1719
                case 'g':
1720
                        if (!par[0])
1721
                                tab_stop[x >> 5] &= ~(1 << (x & 31));
1722
                        else if (par[0] == 3) {
1723
                                tab_stop[0] =
1724
                                        tab_stop[1] =
1725
                                        tab_stop[2] =
1726
                                        tab_stop[3] =
1727
                                        tab_stop[4] = 0;
1728
                        }
1729
                        return;
1730
                case 'm':
1731
                        csi_m(currcons);
1732
                        return;
1733
                case 'q': /* DECLL - but only 3 leds */
1734
                        /* map 0,1,2,3 to 0,1,2,4 */
1735
                        if (par[0] < 4)
1736
                                setledstate(kbd_table + currcons,
1737
                                            (par[0] < 3) ? par[0] : 4);
1738
                        return;
1739
                case 'r':
1740
                        if (!par[0])
1741
                                par[0]++;
1742
                        if (!par[1])
1743
                                par[1] = video_num_lines;
1744
                        /* Minimum allowed region is 2 lines */
1745
                        if (par[0] < par[1] &&
1746
                            par[1] <= video_num_lines) {
1747
                                top=par[0]-1;
1748
                                bottom=par[1];
1749
                                gotoxay(currcons,0,0);
1750
                        }
1751
                        return;
1752
                case 's':
1753
                        save_cur(currcons);
1754
                        return;
1755
                case 'u':
1756
                        restore_cur(currcons);
1757
                        return;
1758
                case 'X':
1759
                        csi_X(currcons, par[0]);
1760
                        return;
1761
                case '@':
1762
                        csi_at(currcons,par[0]);
1763
                        return;
1764
                case ']': /* setterm functions */
1765
                        setterm_command(currcons);
1766
                        return;
1767
                }
1768
                return;
1769
        case ESpercent:
1770
                vc_state = ESnormal;
1771
                switch (c) {
1772
                case '@':  /* defined in ISO 2022 */
1773
                        utf = 0;
1774
                        return;
1775
                case 'G':  /* prelim official escape code */
1776
                case '8':  /* retained for compatibility */
1777
                        utf = 1;
1778
                        return;
1779
                }
1780
                return;
1781
        case ESfunckey:
1782
                vc_state = ESnormal;
1783
                return;
1784
        case EShash:
1785
                vc_state = ESnormal;
1786
                if (c == '8') {
1787
                        /* DEC screen alignment test. kludge :-) */
1788
                        video_erase_char =
1789
                                (video_erase_char & 0xff00) | 'E';
1790
                        csi_J(currcons, 2);
1791
                        video_erase_char =
1792
                                (video_erase_char & 0xff00) | ' ';
1793
                        do_update_region(currcons, origin, screenbuf_size/2);
1794
                }
1795
                return;
1796
        case ESsetG0:
1797
                if (c == '0')
1798
                        G0_charset = GRAF_MAP;
1799
                else if (c == 'B')
1800
                        G0_charset = LAT1_MAP;
1801
                else if (c == 'U')
1802
                        G0_charset = IBMPC_MAP;
1803
                else if (c == 'K')
1804
                        G0_charset = USER_MAP;
1805
                if (charset == 0)
1806
                        translate = set_translate(G0_charset,currcons);
1807
                vc_state = ESnormal;
1808
                return;
1809
        case ESsetG1:
1810
                if (c == '0')
1811
                        G1_charset = GRAF_MAP;
1812
                else if (c == 'B')
1813
                        G1_charset = LAT1_MAP;
1814
                else if (c == 'U')
1815
                        G1_charset = IBMPC_MAP;
1816
                else if (c == 'K')
1817
                        G1_charset = USER_MAP;
1818
                if (charset == 1)
1819
                        translate = set_translate(G1_charset,currcons);
1820
                vc_state = ESnormal;
1821
                return;
1822
        default:
1823
                vc_state = ESnormal;
1824
        }
1825
}
1826
 
1827
/* This is a temporary buffer used to prepare a tty console write
1828
 * so that we can easily avoid touching user space while holding the
1829
 * console spinlock.  It is allocated in con_init and is shared by
1830
 * this code and the vc_screen read/write tty calls.
1831
 *
1832
 * We have to allocate this statically in the kernel data section
1833
 * since console_init (and thus con_init) are called before any
1834
 * kernel memory allocation is available.
1835
 */
1836
char con_buf[PAGE_SIZE];
1837
#define CON_BUF_SIZE    PAGE_SIZE
1838
DECLARE_MUTEX(con_buf_sem);
1839
 
1840
/* acquires console_sem */
1841
static int do_con_write(struct tty_struct * tty, int from_user,
1842
                        const unsigned char *buf, int count)
1843
{
1844
#ifdef VT_BUF_VRAM_ONLY
1845
#define FLUSH do { } while(0);
1846
#else
1847
#define FLUSH if (draw_x >= 0) { \
1848
        sw->con_putcs(vc_cons[currcons].d, (u16 *)draw_from, (u16 *)draw_to-(u16 *)draw_from, y, draw_x); \
1849
        draw_x = -1; \
1850
        }
1851
#endif
1852
 
1853
        int c, tc, ok, n = 0, draw_x = -1;
1854
        unsigned int currcons;
1855
        unsigned long draw_from = 0, draw_to = 0;
1856
        struct vt_struct *vt = (struct vt_struct *)tty->driver_data;
1857
        u16 himask, charmask;
1858
        const unsigned char *orig_buf = NULL;
1859
        int orig_count;
1860
 
1861
        if (in_interrupt())
1862
                return count;
1863
 
1864
        currcons = vt->vc_num;
1865
        if (!vc_cons_allocated(currcons)) {
1866
            /* could this happen? */
1867
            static int error = 0;
1868
            if (!error) {
1869
                error = 1;
1870
                printk("con_write: tty %d not allocated\n", currcons+1);
1871
            }
1872
            return 0;
1873
        }
1874
 
1875
        orig_buf = buf;
1876
        orig_count = count;
1877
 
1878
        if (from_user) {
1879
                down(&con_buf_sem);
1880
 
1881
again:
1882
                if (count > CON_BUF_SIZE)
1883
                        count = CON_BUF_SIZE;
1884
                console_conditional_schedule();
1885
                if (copy_from_user(con_buf, buf, count)) {
1886
                        n = 0; /* ?? are error codes legal here ?? */
1887
                        goto out;
1888
                }
1889
 
1890
                buf = con_buf;
1891
        }
1892
 
1893
        /* At this point 'buf' is guarenteed to be a kernel buffer
1894
         * and therefore no access to userspace (and therefore sleeping)
1895
         * will be needed.  The con_buf_sem serializes all tty based
1896
         * console rendering and vcs write/read operations.  We hold
1897
         * the console spinlock during the entire write.
1898
         */
1899
 
1900
        acquire_console_sem();
1901
 
1902
        himask = hi_font_mask;
1903
        charmask = himask ? 0x1ff : 0xff;
1904
 
1905
        /* undraw cursor first */
1906
        if (IS_FG)
1907
                hide_cursor(currcons);
1908
 
1909
        while (!tty->stopped && count) {
1910
                c = *buf;
1911
                buf++;
1912
                n++;
1913
                count--;
1914
 
1915
                if (utf) {
1916
                    /* Combine UTF-8 into Unicode */
1917
                    /* Incomplete characters silently ignored */
1918
                    if(c > 0x7f) {
1919
                        if (utf_count > 0 && (c & 0xc0) == 0x80) {
1920
                                utf_char = (utf_char << 6) | (c & 0x3f);
1921
                                utf_count--;
1922
                                if (utf_count == 0)
1923
                                    tc = c = utf_char;
1924
                                else continue;
1925
                        } else {
1926
                                if ((c & 0xe0) == 0xc0) {
1927
                                    utf_count = 1;
1928
                                    utf_char = (c & 0x1f);
1929
                                } else if ((c & 0xf0) == 0xe0) {
1930
                                    utf_count = 2;
1931
                                    utf_char = (c & 0x0f);
1932
                                } else if ((c & 0xf8) == 0xf0) {
1933
                                    utf_count = 3;
1934
                                    utf_char = (c & 0x07);
1935
                                } else if ((c & 0xfc) == 0xf8) {
1936
                                    utf_count = 4;
1937
                                    utf_char = (c & 0x03);
1938
                                } else if ((c & 0xfe) == 0xfc) {
1939
                                    utf_count = 5;
1940
                                    utf_char = (c & 0x01);
1941
                                } else
1942
                                    utf_count = 0;
1943
                                continue;
1944
                              }
1945
                    } else {
1946
                      tc = c;
1947
                      utf_count = 0;
1948
                    }
1949
                } else {        /* no utf */
1950
                  tc = translate[toggle_meta ? (c|0x80) : c];
1951
                }
1952
 
1953
                /* If the original code was a control character we
1954
                 * only allow a glyph to be displayed if the code is
1955
                 * not normally used (such as for cursor movement) or
1956
                 * if the disp_ctrl mode has been explicitly enabled.
1957
                 * Certain characters (as given by the CTRL_ALWAYS
1958
                 * bitmap) are always displayed as control characters,
1959
                 * as the console would be pretty useless without
1960
                 * them; to display an arbitrary font position use the
1961
                 * direct-to-font zone in UTF-8 mode.
1962
                 */
1963
                ok = tc && (c >= 32 ||
1964
                            (!utf && !(((disp_ctrl ? CTRL_ALWAYS
1965
                                         : CTRL_ACTION) >> c) & 1)))
1966
                        && (c != 127 || disp_ctrl)
1967
                        && (c != 128+27);
1968
 
1969
                if (vc_state == ESnormal && ok) {
1970
                        /* Now try to find out how to display it */
1971
                        tc = conv_uni_to_pc(vc_cons[currcons].d, tc);
1972
                        if ( tc == -4 ) {
1973
                                /* If we got -4 (not found) then see if we have
1974
                                   defined a replacement character (U+FFFD) */
1975
                                tc = conv_uni_to_pc(vc_cons[currcons].d, 0xfffd);
1976
 
1977
                                /* One reason for the -4 can be that we just
1978
                                   did a clear_unimap();
1979
                                   try at least to show something. */
1980
                                if (tc == -4)
1981
                                     tc = c;
1982
                        } else if ( tc == -3 ) {
1983
                                /* Bad hash table -- hope for the best */
1984
                                tc = c;
1985
                        }
1986
                        if (tc & ~charmask)
1987
                                continue; /* Conversion failed */
1988
 
1989
                        if (need_wrap || decim)
1990
                                FLUSH
1991
                        if (need_wrap) {
1992
                                cr(currcons);
1993
                                lf(currcons);
1994
                        }
1995
                        if (decim)
1996
                                insert_char(currcons, 1);
1997
                        scr_writew(himask ?
1998
                                     ((attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
1999
                                     (attr << 8) + tc,
2000
                                   (u16 *) pos);
2001
                        if (DO_UPDATE && draw_x < 0) {
2002
                                draw_x = x;
2003
                                draw_from = pos;
2004
                        }
2005
                        if (x == video_num_columns - 1) {
2006
                                need_wrap = decawm;
2007
                                draw_to = pos+2;
2008
                        } else {
2009
                                x++;
2010
                                draw_to = (pos+=2);
2011
                        }
2012
                        continue;
2013
                }
2014
                FLUSH
2015
                do_con_trol(tty, currcons, c);
2016
        }
2017
        FLUSH
2018
        console_conditional_schedule();
2019
        release_console_sem();
2020
 
2021
out:
2022
        if (from_user) {
2023
                /* If the user requested something larger than
2024
                 * the CON_BUF_SIZE, and the tty is not stopped,
2025
                 * keep going.
2026
                 */
2027
                if ((orig_count > CON_BUF_SIZE) && !tty->stopped) {
2028
                        orig_count -= CON_BUF_SIZE;
2029
                        orig_buf += CON_BUF_SIZE;
2030
                        count = orig_count;
2031
                        buf = orig_buf;
2032
                        goto again;
2033
                }
2034
 
2035
                up(&con_buf_sem);
2036
        }
2037
 
2038
        return n;
2039
#undef FLUSH
2040
}
2041
 
2042
/*
2043
 * This is the console switching callback.
2044
 *
2045
 * Doing console switching in a process context allows
2046
 * us to do the switches asynchronously (needed when we want
2047
 * to switch due to a keyboard interrupt).  Synchronization
2048
 * with other console code and prevention of re-entrancy is
2049
 * ensured with console_sem.
2050
 */
2051
static void console_callback(void *unused)
2052
{
2053
        acquire_console_sem();
2054
        __console_callback();
2055
        release_console_sem();
2056
}
2057
 
2058
static void __console_callback(void)
2059
{
2060
        if (want_console >= 0) {
2061
                if (want_console != fg_console && vc_cons_allocated(want_console)) {
2062
                        hide_cursor(fg_console);
2063
                        change_console(want_console);
2064
                        /* we only changed when the console had already
2065
                           been allocated - a new console is not created
2066
                           in an interrupt routine */
2067
                }
2068
                want_console = -1;
2069
        }
2070
        if (do_poke_blanked_console) { /* do not unblank for a LED change */
2071
                do_poke_blanked_console = 0;
2072
                poke_blanked_console();
2073
        }
2074
        if (scrollback_delta) {
2075
                int currcons = fg_console;
2076
                clear_selection();
2077
                if (vcmode == KD_TEXT)
2078
                        sw->con_scrolldelta(vc_cons[currcons].d, scrollback_delta);
2079
                scrollback_delta = 0;
2080
        }
2081
}
2082
 
2083
void set_console(int nr)
2084
{
2085
        want_console = nr;
2086
        schedule_console_callback();
2087
}
2088
 
2089
#ifdef CONFIG_VT_CONSOLE
2090
 
2091
/*
2092
 *      Console on virtual terminal
2093
 *
2094
 * The console must be locked when we get here.
2095
 */
2096
 
2097
void vt_console_print(struct console *co, const char * b, unsigned count)
2098
{
2099
        int currcons = fg_console;
2100
        unsigned char c;
2101
        static unsigned long printing;
2102
        const ushort *start;
2103
        ushort cnt = 0;
2104
        ushort myx;
2105
 
2106
        /* console busy or not yet initialized */
2107
        if (!printable || test_and_set_bit(0, &printing))
2108
                return;
2109
 
2110
        pm_access(pm_con);
2111
 
2112
        if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1))
2113
                currcons = kmsg_redirect - 1;
2114
 
2115
        /* read `x' only after setting currecons properly (otherwise
2116
           the `x' macro will read the x of the foreground console). */
2117
        myx = x;
2118
 
2119
        if (!vc_cons_allocated(currcons)) {
2120
                /* impossible */
2121
                /* printk("vt_console_print: tty %d not allocated ??\n", currcons+1); */
2122
                goto quit;
2123
        }
2124
 
2125
        if (vcmode != KD_TEXT)
2126
                goto quit;
2127
 
2128
        /* undraw cursor first */
2129
        if (IS_FG)
2130
                hide_cursor(currcons);
2131
 
2132
        start = (ushort *)pos;
2133
 
2134
        /* Contrived structure to try to emulate original need_wrap behaviour
2135
         * Problems caused when we have need_wrap set on '\n' character */
2136
        while (count--) {
2137
                c = *b++;
2138
                if (c == 10 || c == 13 || c == 8 || need_wrap) {
2139
                        if (cnt > 0) {
2140
                                if (IS_VISIBLE)
2141
                                        sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2142
                                x += cnt;
2143
                                if (need_wrap)
2144
                                        x--;
2145
                                cnt = 0;
2146
                        }
2147
                        if (c == 8) {           /* backspace */
2148
                                bs(currcons);
2149
                                start = (ushort *)pos;
2150
                                myx = x;
2151
                                continue;
2152
                        }
2153
                        if (c != 13)
2154
                                lf(currcons);
2155
                        cr(currcons);
2156
                        start = (ushort *)pos;
2157
                        myx = x;
2158
                        if (c == 10 || c == 13)
2159
                                continue;
2160
                }
2161
                scr_writew((attr << 8) + c, (unsigned short *) pos);
2162
                cnt++;
2163
                if (myx == video_num_columns - 1) {
2164
                        need_wrap = 1;
2165
                        continue;
2166
                }
2167
                pos+=2;
2168
                myx++;
2169
        }
2170
        if (cnt > 0) {
2171
                if (IS_VISIBLE)
2172
                        sw->con_putcs(vc_cons[currcons].d, start, cnt, y, x);
2173
                x += cnt;
2174
                if (x == video_num_columns) {
2175
                        x--;
2176
                        need_wrap = 1;
2177
                }
2178
        }
2179
        set_cursor(currcons);
2180
 
2181
        if (!oops_in_progress)
2182
                poke_blanked_console();
2183
 
2184
quit:
2185
        clear_bit(0, &printing);
2186
}
2187
 
2188
static kdev_t vt_console_device(struct console *c)
2189
{
2190
        return MKDEV(TTY_MAJOR, c->index ? c->index : fg_console + 1);
2191
}
2192
 
2193
struct console vt_console_driver = {
2194
        name:           "tty",
2195
        write:          vt_console_print,
2196
        device:         vt_console_device,
2197
        unblank:        unblank_screen,
2198
        flags:          CON_PRINTBUFFER,
2199
        index:          -1,
2200
};
2201
#endif
2202
 
2203
/*
2204
 *      Handling of Linux-specific VC ioctls
2205
 */
2206
 
2207
/*
2208
 * Generally a bit racy with respect to console_sem().
2209
 *
2210
 * There are some functions which don't need it.
2211
 *
2212
 * There are some functions which can sleep for arbitrary periods (paste_selection)
2213
 * but we don't need the lock there anyway.
2214
 *
2215
 * set_selection has locking, and definitely needs it
2216
 */
2217
 
2218
int tioclinux(struct tty_struct *tty, unsigned long arg)
2219
{
2220
        char type, data;
2221
        int ret;
2222
 
2223
        if (tty->driver.type != TTY_DRIVER_TYPE_CONSOLE)
2224
                return -EINVAL;
2225
        if (current->tty != tty && !capable(CAP_SYS_ADMIN))
2226
                return -EPERM;
2227
        if (get_user(type, (char *)arg))
2228
                return -EFAULT;
2229
        ret = 0;
2230
        switch (type)
2231
        {
2232
                case 2:
2233
                        acquire_console_sem();
2234
                        ret = set_selection(arg, tty, 1);
2235
                        release_console_sem();
2236
                        break;
2237
                case 3:
2238
                        ret = paste_selection(tty);
2239
                        break;
2240
                case 4:
2241
                        unblank_screen();
2242
                        break;
2243
                case 5:
2244
                        ret = sel_loadlut(arg);
2245
                        break;
2246
                case 6:
2247
 
2248
        /*
2249
         * Make it possible to react to Shift+Mousebutton.
2250
         * Note that 'shift_state' is an undocumented
2251
         * kernel-internal variable; programs not closely
2252
         * related to the kernel should not use this.
2253
         */
2254
                        data = shift_state;
2255
                        ret = __put_user(data, (char *) arg);
2256
                        break;
2257
                case 7:
2258
                        data = mouse_reporting();
2259
                        ret = __put_user(data, (char *) arg);
2260
                        break;
2261
                case 10:
2262
                        set_vesa_blanking(arg);
2263
                        break;;
2264
                case 11:        /* set kmsg redirect */
2265
                        if (!capable(CAP_SYS_ADMIN)) {
2266
                                ret = -EPERM;
2267
                        } else {
2268
                                if (get_user(data, (char *)arg+1))
2269
                                        ret = -EFAULT;
2270
                                else
2271
                                        kmsg_redirect = data;
2272
                        }
2273
                        break;
2274
                case 12:        /* get fg_console */
2275
                        ret = fg_console;
2276
                        break;
2277
                default:
2278
                        ret = -EINVAL;
2279
                        break;
2280
        }
2281
        return ret;
2282
}
2283
 
2284
/*
2285
 *      /dev/ttyN handling
2286
 */
2287
 
2288
static int con_write(struct tty_struct * tty, int from_user,
2289
                     const unsigned char *buf, int count)
2290
{
2291
        int     retval;
2292
 
2293
        pm_access(pm_con);
2294
        retval = do_con_write(tty, from_user, buf, count);
2295
        con_flush_chars(tty);
2296
 
2297
        return retval;
2298
}
2299
 
2300
static void con_put_char(struct tty_struct *tty, unsigned char ch)
2301
{
2302
        if (in_interrupt())
2303
                return;         /* n_r3964 calls put_char() from interrupt context */
2304
        pm_access(pm_con);
2305
        do_con_write(tty, 0, &ch, 1);
2306
}
2307
 
2308
static int con_write_room(struct tty_struct *tty)
2309
{
2310
        if (tty->stopped)
2311
                return 0;
2312
        return 4096;            /* No limit, really; we're not buffering */
2313
}
2314
 
2315
static int con_chars_in_buffer(struct tty_struct *tty)
2316
{
2317
        return 0;                /* we're not buffering */
2318
}
2319
 
2320
/*
2321
 * con_throttle and con_unthrottle are only used for
2322
 * paste_selection(), which has to stuff in a large number of
2323
 * characters...
2324
 */
2325
static void con_throttle(struct tty_struct *tty)
2326
{
2327
}
2328
 
2329
static void con_unthrottle(struct tty_struct *tty)
2330
{
2331
        struct vt_struct *vt = (struct vt_struct *) tty->driver_data;
2332
 
2333
        wake_up_interruptible(&vt->paste_wait);
2334
}
2335
 
2336
/*
2337
 * Turn the Scroll-Lock LED on when the tty is stopped
2338
 */
2339
static void con_stop(struct tty_struct *tty)
2340
{
2341
        int console_num;
2342
        if (!tty)
2343
                return;
2344
        console_num = MINOR(tty->device) - (tty->driver.minor_start);
2345
        if (!vc_cons_allocated(console_num))
2346
                return;
2347
        set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2348
        set_leds();
2349
}
2350
 
2351
/*
2352
 * Turn the Scroll-Lock LED off when the console is started
2353
 */
2354
static void con_start(struct tty_struct *tty)
2355
{
2356
        int console_num;
2357
        if (!tty)
2358
                return;
2359
        console_num = MINOR(tty->device) - (tty->driver.minor_start);
2360
        if (!vc_cons_allocated(console_num))
2361
                return;
2362
        clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK);
2363
        set_leds();
2364
}
2365
 
2366
/*
2367
 * we can race here against con_close, so we grab the bkl
2368
 * and check the pointer before calling set_cursor
2369
 */
2370
static void con_flush_chars(struct tty_struct *tty)
2371
{
2372
        struct vt_struct *vt;
2373
 
2374
        if (in_interrupt())     /* from flush_to_ldisc */
2375
                return;
2376
 
2377
        pm_access(pm_con);
2378
        lock_kernel();
2379
        acquire_console_sem();
2380
        vt = (struct vt_struct *)tty->driver_data;
2381
        if (vt)
2382
                set_cursor(vt->vc_num);
2383
        release_console_sem();
2384
        unlock_kernel();
2385
}
2386
 
2387
/*
2388
 * Allocate the console screen memory.
2389
 */
2390
static int con_open(struct tty_struct *tty, struct file * filp)
2391
{
2392
        unsigned int    currcons;
2393
        int i;
2394
 
2395
        currcons = MINOR(tty->device) - tty->driver.minor_start;
2396
 
2397
        i = vc_allocate(currcons);
2398
        if (i)
2399
                return i;
2400
 
2401
        vt_cons[currcons]->vc_num = currcons;
2402
        tty->driver_data = vt_cons[currcons];
2403
 
2404
        if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
2405
                tty->winsize.ws_row = video_num_lines;
2406
                tty->winsize.ws_col = video_num_columns;
2407
        }
2408
        if (tty->count == 1)
2409
                vcs_make_devfs (currcons, 0);
2410
        return 0;
2411
}
2412
 
2413
static void con_close(struct tty_struct *tty, struct file * filp)
2414
{
2415
        if (!tty)
2416
                return;
2417
        if (tty->count != 1) return;
2418
        vcs_make_devfs (MINOR (tty->device) - tty->driver.minor_start, 1);
2419
        tty->driver_data = 0;
2420
}
2421
 
2422
static void vc_init(unsigned int currcons, unsigned int rows, unsigned int cols, int do_clear)
2423
{
2424
        int j, k ;
2425
 
2426
        video_num_columns = cols;
2427
        video_num_lines = rows;
2428
        video_size_row = cols<<1;
2429
        screenbuf_size = video_num_lines * video_size_row;
2430
 
2431
        set_origin(currcons);
2432
        pos = origin;
2433
        reset_vc(currcons);
2434
        for (j=k=0; j<16; j++) {
2435
                vc_cons[currcons].d->vc_palette[k++] = default_red[j] ;
2436
                vc_cons[currcons].d->vc_palette[k++] = default_grn[j] ;
2437
                vc_cons[currcons].d->vc_palette[k++] = default_blu[j] ;
2438
        }
2439
        def_color       = 0x07;   /* white */
2440
        ulcolor         = 0x0f;   /* bold white */
2441
        halfcolor       = 0x08;   /* grey */
2442
        init_waitqueue_head(&vt_cons[currcons]->paste_wait);
2443
        reset_terminal(currcons, do_clear);
2444
}
2445
 
2446
/*
2447
 * This routine initializes console interrupts, and does nothing
2448
 * else. If you want the screen to clear, call tty_write with
2449
 * the appropriate escape-sequence.
2450
 */
2451
 
2452
struct tty_driver console_driver;
2453
static int console_refcount;
2454
 
2455
void __init con_init(void)
2456
{
2457
        const char *display_desc = NULL;
2458
        unsigned int currcons = 0;
2459
 
2460
        if (conswitchp)
2461
                display_desc = conswitchp->con_startup();
2462
        if (!display_desc) {
2463
                fg_console = 0;
2464
                return;
2465
        }
2466
 
2467
        memset(&console_driver, 0, sizeof(struct tty_driver));
2468
        console_driver.magic = TTY_DRIVER_MAGIC;
2469
        console_driver.name = "vc/%d";
2470
        console_driver.name_base = 1;
2471
        console_driver.major = TTY_MAJOR;
2472
        console_driver.minor_start = 1;
2473
        console_driver.num = MAX_NR_CONSOLES;
2474
        console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
2475
        console_driver.init_termios = tty_std_termios;
2476
        console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
2477
        /* Tell tty_register_driver() to skip consoles because they are
2478
         * registered before kmalloc() is ready. We'll patch them in later.
2479
         * See comments at console_init(); see also con_init_devfs().
2480
         */
2481
        console_driver.flags |= TTY_DRIVER_NO_DEVFS;
2482
        console_driver.refcount = &console_refcount;
2483
        console_driver.table = console_table;
2484
        console_driver.termios = console_termios;
2485
        console_driver.termios_locked = console_termios_locked;
2486
 
2487
        console_driver.open = con_open;
2488
        console_driver.close = con_close;
2489
        console_driver.write = con_write;
2490
        console_driver.write_room = con_write_room;
2491
        console_driver.put_char = con_put_char;
2492
        console_driver.flush_chars = con_flush_chars;
2493
        console_driver.chars_in_buffer = con_chars_in_buffer;
2494
        console_driver.ioctl = vt_ioctl;
2495
        console_driver.stop = con_stop;
2496
        console_driver.start = con_start;
2497
        console_driver.throttle = con_throttle;
2498
        console_driver.unthrottle = con_unthrottle;
2499
 
2500
        if (tty_register_driver(&console_driver))
2501
                panic("Couldn't register console driver\n");
2502
 
2503
        init_timer(&console_timer);
2504
        console_timer.function = blank_screen;
2505
        if (blankinterval) {
2506
                mod_timer(&console_timer, jiffies + blankinterval);
2507
        }
2508
 
2509
        /*
2510
         * kmalloc is not running yet - we use the bootmem allocator.
2511
         */
2512
        for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
2513
                vc_cons[currcons].d = (struct vc_data *)
2514
                                alloc_bootmem(sizeof(struct vc_data));
2515
                vt_cons[currcons] = (struct vt_struct *)
2516
                                alloc_bootmem(sizeof(struct vt_struct));
2517
                visual_init(currcons, 1);
2518
                screenbuf = (unsigned short *) alloc_bootmem(screenbuf_size);
2519
                kmalloced = 0;
2520
                vc_init(currcons, video_num_lines, video_num_columns,
2521
                        currcons || !sw->con_save_screen);
2522
        }
2523
        currcons = fg_console = 0;
2524
        master_display_fg = vc_cons[currcons].d;
2525
        set_origin(currcons);
2526
        save_screen(currcons);
2527
        gotoxy(currcons,x,y);
2528
        csi_J(currcons, 0);
2529
        update_screen(fg_console);
2530
        printk("Console: %s %s %dx%d",
2531
                can_do_color ? "colour" : "mono",
2532
                display_desc, video_num_columns, video_num_lines);
2533
        printable = 1;
2534
        printk("\n");
2535
 
2536
#ifdef CONFIG_VT_CONSOLE
2537
        register_console(&vt_console_driver);
2538
#endif
2539
}
2540
 
2541
#ifndef VT_SINGLE_DRIVER
2542
 
2543
static void clear_buffer_attributes(int currcons)
2544
{
2545
        unsigned short *p = (unsigned short *) origin;
2546
        int count = screenbuf_size/2;
2547
        int mask = hi_font_mask | 0xff;
2548
 
2549
        for (; count > 0; count--, p++) {
2550
                scr_writew((scr_readw(p)&mask) | (video_erase_char&~mask), p);
2551
        }
2552
}
2553
 
2554
/*
2555
 *      If we support more console drivers, this function is used
2556
 *      when a driver wants to take over some existing consoles
2557
 *      and become default driver for newly opened ones.
2558
 */
2559
 
2560
void take_over_console(const struct consw *csw, int first, int last, int deflt)
2561
{
2562
        int i, j = -1;
2563
        const char *desc;
2564
 
2565
        desc = csw->con_startup();
2566
        if (!desc) return;
2567
        if (deflt)
2568
                conswitchp = csw;
2569
 
2570
        for (i = first; i <= last; i++) {
2571
                int old_was_color;
2572
                int currcons = i;
2573
 
2574
                con_driver_map[i] = csw;
2575
 
2576
                if (!vc_cons[i].d || !vc_cons[i].d->vc_sw)
2577
                        continue;
2578
 
2579
                j = i;
2580
                if (IS_VISIBLE)
2581
                        save_screen(i);
2582
                old_was_color = vc_cons[i].d->vc_can_do_color;
2583
                vc_cons[i].d->vc_sw->con_deinit(vc_cons[i].d);
2584
                visual_init(i, 0);
2585
                update_attr(i);
2586
 
2587
                /* If the console changed between mono <-> color, then
2588
                 * the attributes in the screenbuf will be wrong.  The
2589
                 * following resets all attributes to something sane.
2590
                 */
2591
                if (old_was_color != vc_cons[i].d->vc_can_do_color)
2592
                        clear_buffer_attributes(i);
2593
 
2594
                if (IS_VISIBLE)
2595
                        update_screen(i);
2596
        }
2597
        printk("Console: switching ");
2598
        if (!deflt)
2599
                printk("consoles %d-%d ", first+1, last+1);
2600
        if (j >= 0)
2601
                printk("to %s %s %dx%d\n",
2602
                       vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
2603
                       desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
2604
        else
2605
                printk("to %s\n", desc);
2606
}
2607
 
2608
void give_up_console(const struct consw *csw)
2609
{
2610
        int i;
2611
 
2612
        for(i = 0; i < MAX_NR_CONSOLES; i++)
2613
                if (con_driver_map[i] == csw)
2614
                        con_driver_map[i] = NULL;
2615
}
2616
 
2617
#endif
2618
 
2619
/*
2620
 *      Screen blanking
2621
 */
2622
 
2623
static void set_vesa_blanking(unsigned long arg)
2624
{
2625
        char *argp = (char *)arg + 1;
2626
        unsigned int mode;
2627
        if (get_user(mode, argp) == 0)
2628
                vesa_blank_mode = (mode < 4) ? mode : 0;
2629
}
2630
 
2631
/* We can't register the console with devfs during con_init(), because it
2632
 * is called before kmalloc() works.  This function is called later to
2633
 * do the registration.
2634
 */
2635
void __init con_init_devfs (void)
2636
{
2637
        int i;
2638
 
2639
        for (i = 0; i < console_driver.num; i++)
2640
                tty_register_devfs (&console_driver, DEVFS_FL_AOPEN_NOTIFY,
2641
                                    console_driver.minor_start + i);
2642
}
2643
 
2644
/*
2645
 * This is called by a timer handler
2646
 */
2647
static void vesa_powerdown(void)
2648
{
2649
    struct vc_data *c = vc_cons[fg_console].d;
2650
    /*
2651
     *  Power down if currently suspended (1 or 2),
2652
     *  suspend if currently blanked (0),
2653
     *  else do nothing (i.e. already powered down (3)).
2654
     *  Called only if powerdown features are allowed.
2655
     */
2656
    switch (vesa_blank_mode) {
2657
        case VESA_NO_BLANKING:
2658
            c->vc_sw->con_blank(c, VESA_VSYNC_SUSPEND+1);
2659
            break;
2660
        case VESA_VSYNC_SUSPEND:
2661
        case VESA_HSYNC_SUSPEND:
2662
            c->vc_sw->con_blank(c, VESA_POWERDOWN+1);
2663
            break;
2664
    }
2665
}
2666
 
2667
/*
2668
 * This is a timer handler
2669
 */
2670
static void vesa_powerdown_screen(unsigned long dummy)
2671
{
2672
        console_timer.function = unblank_screen_t;
2673
 
2674
        vesa_powerdown();
2675
}
2676
 
2677
static void timer_do_blank_screen(int entering_gfx, int from_timer_handler)
2678
{
2679
        int currcons = fg_console;
2680
        int i;
2681
 
2682
        if (console_blanked)
2683
                return;
2684
 
2685
        /* entering graphics mode? */
2686
        if (entering_gfx) {
2687
                hide_cursor(currcons);
2688
                save_screen(currcons);
2689
                sw->con_blank(vc_cons[currcons].d, -1);
2690
                console_blanked = fg_console + 1;
2691
                set_origin(currcons);
2692
                return;
2693
        }
2694
 
2695
        /* don't blank graphics */
2696
        if (vcmode != KD_TEXT) {
2697
                console_blanked = fg_console + 1;
2698
                return;
2699
        }
2700
 
2701
        hide_cursor(currcons);
2702
        if (!from_timer_handler)
2703
                del_timer_sync(&console_timer);
2704
        if (vesa_off_interval) {
2705
                console_timer.function = vesa_powerdown_screen;
2706
                mod_timer(&console_timer, jiffies + vesa_off_interval);
2707
        } else {
2708
                if (!from_timer_handler)
2709
                        del_timer_sync(&console_timer);
2710
                console_timer.function = unblank_screen_t;
2711
        }
2712
 
2713
        save_screen(currcons);
2714
        /* In case we need to reset origin, blanking hook returns 1 */
2715
        i = sw->con_blank(vc_cons[currcons].d, 1);
2716
        console_blanked = fg_console + 1;
2717
        if (i)
2718
                set_origin(currcons);
2719
 
2720
        if (console_blank_hook && console_blank_hook(1))
2721
                return;
2722
        if (vesa_blank_mode)
2723
                sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1);
2724
}
2725
 
2726
void do_blank_screen(int entering_gfx)
2727
{
2728
        timer_do_blank_screen(entering_gfx, 0);
2729
}
2730
 
2731
/*
2732
 * This is a timer handler
2733
 */
2734
static void unblank_screen_t(unsigned long dummy)
2735
{
2736
        unblank_screen();
2737
}
2738
 
2739
/*
2740
 * Called by timer as well as from vt_console_driver
2741
 */
2742
void unblank_screen(void)
2743
{
2744
        int currcons;
2745
 
2746
        if (!console_blanked)
2747
                return;
2748
        if (!vc_cons_allocated(fg_console)) {
2749
                /* impossible */
2750
                printk("unblank_screen: tty %d not allocated ??\n", fg_console+1);
2751
                return;
2752
        }
2753
        currcons = fg_console;
2754
        if (vcmode != KD_TEXT)
2755
                return; /* but leave console_blanked != 0 */
2756
 
2757
        console_timer.function = blank_screen;
2758
        if (blankinterval) {
2759
                mod_timer(&console_timer, jiffies + blankinterval);
2760
        }
2761
 
2762
        console_blanked = 0;
2763
        if (console_blank_hook)
2764
                console_blank_hook(0);
2765
        set_palette(currcons);
2766
        if (sw->con_blank(vc_cons[currcons].d, 0))
2767
                /* Low-level driver cannot restore -> do it ourselves */
2768
                update_screen(fg_console);
2769
        set_cursor(fg_console);
2770
}
2771
 
2772
/*
2773
 * This is both a user-level callable and a timer handler
2774
 */
2775
static void blank_screen(unsigned long dummy)
2776
{
2777
        timer_do_blank_screen(0, 1);
2778
}
2779
 
2780
void disable_console_blank(void)
2781
{
2782
        del_timer_sync(&console_timer);
2783
        blankinterval = 0;
2784
}
2785
 
2786
void poke_blanked_console(void)
2787
{
2788
        del_timer(&console_timer);
2789
        if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
2790
                return;
2791
        if (console_blanked) {
2792
                console_timer.function = unblank_screen_t;
2793
                mod_timer(&console_timer, jiffies);     /* Now */
2794
        } else if (blankinterval) {
2795
                mod_timer(&console_timer, jiffies + blankinterval);
2796
        }
2797
}
2798
 
2799
/*
2800
 *      Palettes
2801
 */
2802
 
2803
void set_palette(int currcons)
2804
{
2805
        if (vcmode != KD_GRAPHICS)
2806
                sw->con_set_palette(vc_cons[currcons].d, color_table);
2807
}
2808
 
2809
static int set_get_cmap(unsigned char *arg, int set)
2810
{
2811
    int i, j, k;
2812
 
2813
    for (i = 0; i < 16; i++)
2814
        if (set) {
2815
            get_user(default_red[i], arg++);
2816
            get_user(default_grn[i], arg++);
2817
            get_user(default_blu[i], arg++);
2818
        } else {
2819
            put_user(default_red[i], arg++);
2820
            put_user(default_grn[i], arg++);
2821
            put_user(default_blu[i], arg++);
2822
        }
2823
    if (set) {
2824
        for (i = 0; i < MAX_NR_CONSOLES; i++)
2825
            if (vc_cons_allocated(i)) {
2826
                for (j = k = 0; j < 16; j++) {
2827
                    vc_cons[i].d->vc_palette[k++] = default_red[j];
2828
                    vc_cons[i].d->vc_palette[k++] = default_grn[j];
2829
                    vc_cons[i].d->vc_palette[k++] = default_blu[j];
2830
                }
2831
                set_palette(i);
2832
            }
2833
    }
2834
    return 0;
2835
}
2836
 
2837
/*
2838
 * Load palette into the DAC registers. arg points to a colour
2839
 * map, 3 bytes per colour, 16 colours, range from 0 to 255.
2840
 */
2841
 
2842
int con_set_cmap(unsigned char *arg)
2843
{
2844
        return set_get_cmap (arg,1);
2845
}
2846
 
2847
int con_get_cmap(unsigned char *arg)
2848
{
2849
        return set_get_cmap (arg,0);
2850
}
2851
 
2852
void reset_palette(int currcons)
2853
{
2854
        int j, k;
2855
        for (j=k=0; j<16; j++) {
2856
                palette[k++] = default_red[j];
2857
                palette[k++] = default_grn[j];
2858
                palette[k++] = default_blu[j];
2859
        }
2860
        set_palette(currcons);
2861
}
2862
 
2863
/*
2864
 *  Font switching
2865
 *
2866
 *  Currently we only support fonts up to 32 pixels wide, at a maximum height
2867
 *  of 32 pixels. Userspace fontdata is stored with 32 bytes (shorts/ints,
2868
 *  depending on width) reserved for each character which is kinda wasty, but
2869
 *  this is done in order to maintain compatibility with the EGA/VGA fonts. It
2870
 *  is upto the actual low-level console-driver convert data into its favorite
2871
 *  format (maybe we should add a `fontoffset' field to the `display'
2872
 *  structure so we wont have to convert the fontdata all the time.
2873
 *  /Jes
2874
 */
2875
 
2876
#define max_font_size 65536
2877
 
2878
int con_font_op(int currcons, struct console_font_op *op)
2879
{
2880
        int rc = -EINVAL;
2881
        int size = max_font_size, set;
2882
        u8 *temp = NULL;
2883
        struct console_font_op old_op;
2884
 
2885
        if (vt_cons[currcons]->vc_mode != KD_TEXT)
2886
                goto quit;
2887
        memcpy(&old_op, op, sizeof(old_op));
2888
        if (op->op == KD_FONT_OP_SET) {
2889
                if (!op->data)
2890
                        return -EINVAL;
2891
                if (op->charcount > 512)
2892
                        goto quit;
2893
                if (!op->height) {              /* Need to guess font height [compat] */
2894
                        int h, i;
2895
                        u8 *charmap = op->data, tmp;
2896
 
2897
                        /* If from KDFONTOP ioctl, don't allow things which can be done in userland,
2898
                           so that we can get rid of this soon */
2899
                        if (!(op->flags & KD_FONT_FLAG_OLD))
2900
                                goto quit;
2901
                        rc = -EFAULT;
2902
                        for (h = 32; h > 0; h--)
2903
                                for (i = 0; i < op->charcount; i++) {
2904
                                        if (get_user(tmp, &charmap[32*i+h-1]))
2905
                                                goto quit;
2906
                                        if (tmp)
2907
                                                goto nonzero;
2908
                                }
2909
                        rc = -EINVAL;
2910
                        goto quit;
2911
                nonzero:
2912
                        rc = -EINVAL;
2913
                        op->height = h;
2914
                }
2915
                if (op->width > 32 || op->height > 32)
2916
                        goto quit;
2917
                size = (op->width+7)/8 * 32 * op->charcount;
2918
                if (size > max_font_size)
2919
                        return -ENOSPC;
2920
                set = 1;
2921
        } else if (op->op == KD_FONT_OP_GET)
2922
                set = 0;
2923
        else
2924
                return sw->con_font_op(vc_cons[currcons].d, op);
2925
        if (op->data) {
2926
                temp = kmalloc(size, GFP_KERNEL);
2927
                if (!temp)
2928
                        return -ENOMEM;
2929
                if (set && copy_from_user(temp, op->data, size)) {
2930
                        rc = -EFAULT;
2931
                        goto quit;
2932
                }
2933
                op->data = temp;
2934
        }
2935
 
2936
        acquire_console_sem();
2937
        rc = sw->con_font_op(vc_cons[currcons].d, op);
2938
        release_console_sem();
2939
 
2940
        op->data = old_op.data;
2941
        if (!rc && !set) {
2942
                int c = (op->width+7)/8 * 32 * op->charcount;
2943
 
2944
                if (op->data && op->charcount > old_op.charcount)
2945
                        rc = -ENOSPC;
2946
                if (!(op->flags & KD_FONT_FLAG_OLD)) {
2947
                        if (op->width > old_op.width ||
2948
                            op->height > old_op.height)
2949
                                rc = -ENOSPC;
2950
                } else {
2951
                        if (op->width != 8)
2952
                                rc = -EIO;
2953
                        else if ((old_op.height && op->height > old_op.height) ||
2954
                                 op->height > 32)
2955
                                rc = -ENOSPC;
2956
                }
2957
                if (!rc && op->data && copy_to_user(op->data, temp, c))
2958
                        rc = -EFAULT;
2959
        }
2960
quit:   if (temp)
2961
                kfree(temp);
2962
        return rc;
2963
}
2964
 
2965
/*
2966
 *      Interface exported to selection and vcs.
2967
 */
2968
 
2969
/* used by selection */
2970
u16 screen_glyph(int currcons, int offset)
2971
{
2972
        u16 w = scr_readw(screenpos(currcons, offset, 1));
2973
        u16 c = w & 0xff;
2974
 
2975
        if (w & hi_font_mask)
2976
                c |= 0x100;
2977
        return c;
2978
}
2979
 
2980
/* used by vcs - note the word offset */
2981
unsigned short *screen_pos(int currcons, int w_offset, int viewed)
2982
{
2983
        return screenpos(currcons, 2 * w_offset, viewed);
2984
}
2985
 
2986
void getconsxy(int currcons, char *p)
2987
{
2988
        p[0] = x;
2989
        p[1] = y;
2990
}
2991
 
2992
void putconsxy(int currcons, char *p)
2993
{
2994
        gotoxy(currcons, p[0], p[1]);
2995
        set_cursor(currcons);
2996
}
2997
 
2998
u16 vcs_scr_readw(int currcons, const u16 *org)
2999
{
3000
        if ((unsigned long)org == pos && softcursor_original != -1)
3001
                return softcursor_original;
3002
        return scr_readw(org);
3003
}
3004
 
3005
void vcs_scr_writew(int currcons, u16 val, u16 *org)
3006
{
3007
        scr_writew(val, org);
3008
        if ((unsigned long)org == pos) {
3009
                softcursor_original = -1;
3010
                add_softcursor(currcons);
3011
        }
3012
}
3013
 
3014
static int pm_con_request(struct pm_dev *dev, pm_request_t rqst, void *data)
3015
{
3016
        switch (rqst)
3017
        {
3018
        case PM_RESUME:
3019
                unblank_screen();
3020
                break;
3021
        case PM_SUSPEND:
3022
                do_blank_screen(0);
3023
                break;
3024
        }
3025
        return 0;
3026
}
3027
 
3028
/*
3029
 *      Visible symbols for modules
3030
 */
3031
 
3032
EXPORT_SYMBOL(color_table);
3033
EXPORT_SYMBOL(default_red);
3034
EXPORT_SYMBOL(default_grn);
3035
EXPORT_SYMBOL(default_blu);
3036
EXPORT_SYMBOL(video_font_height);
3037
EXPORT_SYMBOL(video_scan_lines);
3038
EXPORT_SYMBOL(vc_resize);
3039
EXPORT_SYMBOL(fg_console);
3040
EXPORT_SYMBOL(console_blank_hook);
3041
#ifdef CONFIG_VT
3042
EXPORT_SYMBOL(vt_cons);
3043
#endif
3044
#ifndef VT_SINGLE_DRIVER
3045
EXPORT_SYMBOL(take_over_console);
3046
EXPORT_SYMBOL(give_up_console);
3047
#endif

powered by: WebSVN 2.1.0

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