0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074 #include <linux/module.h>
0075 #include <linux/types.h>
0076 #include <linux/sched/signal.h>
0077 #include <linux/tty.h>
0078 #include <linux/tty_flip.h>
0079 #include <linux/kernel.h>
0080 #include <linux/string.h>
0081 #include <linux/errno.h>
0082 #include <linux/kd.h>
0083 #include <linux/slab.h>
0084 #include <linux/vmalloc.h>
0085 #include <linux/major.h>
0086 #include <linux/mm.h>
0087 #include <linux/console.h>
0088 #include <linux/init.h>
0089 #include <linux/mutex.h>
0090 #include <linux/vt_kern.h>
0091 #include <linux/selection.h>
0092 #include <linux/tiocl.h>
0093 #include <linux/kbd_kern.h>
0094 #include <linux/consolemap.h>
0095 #include <linux/timer.h>
0096 #include <linux/interrupt.h>
0097 #include <linux/workqueue.h>
0098 #include <linux/pm.h>
0099 #include <linux/font.h>
0100 #include <linux/bitops.h>
0101 #include <linux/notifier.h>
0102 #include <linux/device.h>
0103 #include <linux/io.h>
0104 #include <linux/uaccess.h>
0105 #include <linux/kdb.h>
0106 #include <linux/ctype.h>
0107 #include <linux/bsearch.h>
0108 #include <linux/gcd.h>
0109
0110 #define MAX_NR_CON_DRIVER 16
0111
0112 #define CON_DRIVER_FLAG_MODULE 1
0113 #define CON_DRIVER_FLAG_INIT 2
0114 #define CON_DRIVER_FLAG_ATTR 4
0115 #define CON_DRIVER_FLAG_ZOMBIE 8
0116
0117 struct con_driver {
0118 const struct consw *con;
0119 const char *desc;
0120 struct device *dev;
0121 int node;
0122 int first;
0123 int last;
0124 int flag;
0125 };
0126
0127 static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
0128 const struct consw *conswitchp;
0129
0130
0131
0132
0133 #define DEFAULT_BELL_PITCH 750
0134 #define DEFAULT_BELL_DURATION (HZ/8)
0135 #define DEFAULT_CURSOR_BLINK_MS 200
0136
0137 struct vc vc_cons [MAX_NR_CONSOLES];
0138
0139 #ifndef VT_SINGLE_DRIVER
0140 static const struct consw *con_driver_map[MAX_NR_CONSOLES];
0141 #endif
0142
0143 static int con_open(struct tty_struct *, struct file *);
0144 static void vc_init(struct vc_data *vc, unsigned int rows,
0145 unsigned int cols, int do_clear);
0146 static void gotoxy(struct vc_data *vc, int new_x, int new_y);
0147 static void save_cur(struct vc_data *vc);
0148 static void reset_terminal(struct vc_data *vc, int do_clear);
0149 static void con_flush_chars(struct tty_struct *tty);
0150 static int set_vesa_blanking(char __user *p);
0151 static void set_cursor(struct vc_data *vc);
0152 static void hide_cursor(struct vc_data *vc);
0153 static void console_callback(struct work_struct *ignored);
0154 static void con_driver_unregister_callback(struct work_struct *ignored);
0155 static void blank_screen_t(struct timer_list *unused);
0156 static void set_palette(struct vc_data *vc);
0157
0158 #define vt_get_kmsg_redirect() vt_kmsg_redirect(-1)
0159
0160 static int printable;
0161 int default_utf8 = true;
0162 module_param(default_utf8, int, S_IRUGO | S_IWUSR);
0163 int global_cursor_default = -1;
0164 module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
0165
0166 static int cur_default = CUR_UNDERLINE;
0167 module_param(cur_default, int, S_IRUGO | S_IWUSR);
0168
0169
0170
0171
0172
0173 static int ignore_poke;
0174
0175 int do_poke_blanked_console;
0176 int console_blanked;
0177
0178 static int vesa_blank_mode;
0179 static int vesa_off_interval;
0180 static int blankinterval;
0181 core_param(consoleblank, blankinterval, int, 0444);
0182
0183 static DECLARE_WORK(console_work, console_callback);
0184 static DECLARE_WORK(con_driver_unregister_work, con_driver_unregister_callback);
0185
0186
0187
0188
0189
0190
0191
0192 int fg_console;
0193 int last_console;
0194 int want_console = -1;
0195 static int saved_fg_console;
0196 static int saved_last_console;
0197 static int saved_want_console;
0198 static int saved_vc_mode;
0199 static int saved_console_blanked;
0200
0201
0202
0203
0204
0205
0206
0207 static struct vc_data *master_display_fg;
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219 static int scrollback_delta;
0220
0221
0222
0223
0224
0225 int (*console_blank_hook)(int);
0226
0227 static DEFINE_TIMER(console_timer, blank_screen_t);
0228 static int blank_state;
0229 static int blank_timer_expired;
0230 enum {
0231 blank_off = 0,
0232 blank_normal_wait,
0233 blank_vesa_wait,
0234 };
0235
0236
0237
0238
0239
0240
0241
0242 static struct device *tty0dev;
0243
0244
0245
0246
0247 static ATOMIC_NOTIFIER_HEAD(vt_notifier_list);
0248
0249 int register_vt_notifier(struct notifier_block *nb)
0250 {
0251 return atomic_notifier_chain_register(&vt_notifier_list, nb);
0252 }
0253 EXPORT_SYMBOL_GPL(register_vt_notifier);
0254
0255 int unregister_vt_notifier(struct notifier_block *nb)
0256 {
0257 return atomic_notifier_chain_unregister(&vt_notifier_list, nb);
0258 }
0259 EXPORT_SYMBOL_GPL(unregister_vt_notifier);
0260
0261 static void notify_write(struct vc_data *vc, unsigned int unicode)
0262 {
0263 struct vt_notifier_param param = { .vc = vc, .c = unicode };
0264 atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, ¶m);
0265 }
0266
0267 static void notify_update(struct vc_data *vc)
0268 {
0269 struct vt_notifier_param param = { .vc = vc };
0270 atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, ¶m);
0271 }
0272
0273
0274
0275
0276 static inline bool con_is_fg(const struct vc_data *vc)
0277 {
0278 return vc->vc_num == fg_console;
0279 }
0280
0281 static inline bool con_should_update(const struct vc_data *vc)
0282 {
0283 return con_is_visible(vc) && !console_blanked;
0284 }
0285
0286 static inline unsigned short *screenpos(const struct vc_data *vc, int offset,
0287 bool viewed)
0288 {
0289 unsigned short *p;
0290
0291 if (!viewed)
0292 p = (unsigned short *)(vc->vc_origin + offset);
0293 else if (!vc->vc_sw->con_screen_pos)
0294 p = (unsigned short *)(vc->vc_visible_origin + offset);
0295 else
0296 p = vc->vc_sw->con_screen_pos(vc, offset);
0297 return p;
0298 }
0299
0300
0301 static inline void scrolldelta(int lines)
0302 {
0303
0304
0305
0306 scrollback_delta += lines;
0307 schedule_console_callback();
0308 }
0309
0310 void schedule_console_callback(void)
0311 {
0312 schedule_work(&console_work);
0313 }
0314
0315
0316
0317
0318
0319 #ifdef NO_VC_UNI_SCREEN
0320
0321 #define get_vc_uniscr(vc) NULL
0322 #else
0323 #define get_vc_uniscr(vc) vc->vc_uni_screen
0324 #endif
0325
0326 #define VC_UNI_SCREEN_DEBUG 0
0327
0328 typedef uint32_t char32_t;
0329
0330
0331
0332
0333
0334 struct uni_screen {
0335 char32_t *lines[0];
0336 };
0337
0338 static struct uni_screen *vc_uniscr_alloc(unsigned int cols, unsigned int rows)
0339 {
0340 struct uni_screen *uniscr;
0341 void *p;
0342 unsigned int memsize, i;
0343
0344
0345 memsize = cols * rows * sizeof(char32_t);
0346 memsize += rows * sizeof(char32_t *);
0347 p = vzalloc(memsize);
0348 if (!p)
0349 return NULL;
0350
0351
0352 uniscr = p;
0353 p = uniscr->lines + rows;
0354 for (i = 0; i < rows; i++) {
0355 uniscr->lines[i] = p;
0356 p += cols * sizeof(char32_t);
0357 }
0358 return uniscr;
0359 }
0360
0361 static void vc_uniscr_free(struct uni_screen *uniscr)
0362 {
0363 vfree(uniscr);
0364 }
0365
0366 static void vc_uniscr_set(struct vc_data *vc, struct uni_screen *new_uniscr)
0367 {
0368 vc_uniscr_free(vc->vc_uni_screen);
0369 vc->vc_uni_screen = new_uniscr;
0370 }
0371
0372 static void vc_uniscr_putc(struct vc_data *vc, char32_t uc)
0373 {
0374 struct uni_screen *uniscr = get_vc_uniscr(vc);
0375
0376 if (uniscr)
0377 uniscr->lines[vc->state.y][vc->state.x] = uc;
0378 }
0379
0380 static void vc_uniscr_insert(struct vc_data *vc, unsigned int nr)
0381 {
0382 struct uni_screen *uniscr = get_vc_uniscr(vc);
0383
0384 if (uniscr) {
0385 char32_t *ln = uniscr->lines[vc->state.y];
0386 unsigned int x = vc->state.x, cols = vc->vc_cols;
0387
0388 memmove(&ln[x + nr], &ln[x], (cols - x - nr) * sizeof(*ln));
0389 memset32(&ln[x], ' ', nr);
0390 }
0391 }
0392
0393 static void vc_uniscr_delete(struct vc_data *vc, unsigned int nr)
0394 {
0395 struct uni_screen *uniscr = get_vc_uniscr(vc);
0396
0397 if (uniscr) {
0398 char32_t *ln = uniscr->lines[vc->state.y];
0399 unsigned int x = vc->state.x, cols = vc->vc_cols;
0400
0401 memcpy(&ln[x], &ln[x + nr], (cols - x - nr) * sizeof(*ln));
0402 memset32(&ln[cols - nr], ' ', nr);
0403 }
0404 }
0405
0406 static void vc_uniscr_clear_line(struct vc_data *vc, unsigned int x,
0407 unsigned int nr)
0408 {
0409 struct uni_screen *uniscr = get_vc_uniscr(vc);
0410
0411 if (uniscr) {
0412 char32_t *ln = uniscr->lines[vc->state.y];
0413
0414 memset32(&ln[x], ' ', nr);
0415 }
0416 }
0417
0418 static void vc_uniscr_clear_lines(struct vc_data *vc, unsigned int y,
0419 unsigned int nr)
0420 {
0421 struct uni_screen *uniscr = get_vc_uniscr(vc);
0422
0423 if (uniscr) {
0424 unsigned int cols = vc->vc_cols;
0425
0426 while (nr--)
0427 memset32(uniscr->lines[y++], ' ', cols);
0428 }
0429 }
0430
0431 static void vc_uniscr_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
0432 enum con_scroll dir, unsigned int nr)
0433 {
0434 struct uni_screen *uniscr = get_vc_uniscr(vc);
0435
0436 if (uniscr) {
0437 unsigned int i, j, k, sz, d, clear;
0438
0439 sz = b - t;
0440 clear = b - nr;
0441 d = nr;
0442 if (dir == SM_DOWN) {
0443 clear = t;
0444 d = sz - nr;
0445 }
0446 for (i = 0; i < gcd(d, sz); i++) {
0447 char32_t *tmp = uniscr->lines[t + i];
0448 j = i;
0449 while (1) {
0450 k = j + d;
0451 if (k >= sz)
0452 k -= sz;
0453 if (k == i)
0454 break;
0455 uniscr->lines[t + j] = uniscr->lines[t + k];
0456 j = k;
0457 }
0458 uniscr->lines[t + j] = tmp;
0459 }
0460 vc_uniscr_clear_lines(vc, clear, nr);
0461 }
0462 }
0463
0464 static void vc_uniscr_copy_area(struct uni_screen *dst,
0465 unsigned int dst_cols,
0466 unsigned int dst_rows,
0467 struct uni_screen *src,
0468 unsigned int src_cols,
0469 unsigned int src_top_row,
0470 unsigned int src_bot_row)
0471 {
0472 unsigned int dst_row = 0;
0473
0474 if (!dst)
0475 return;
0476
0477 while (src_top_row < src_bot_row) {
0478 char32_t *src_line = src->lines[src_top_row];
0479 char32_t *dst_line = dst->lines[dst_row];
0480
0481 memcpy(dst_line, src_line, src_cols * sizeof(char32_t));
0482 if (dst_cols - src_cols)
0483 memset32(dst_line + src_cols, ' ', dst_cols - src_cols);
0484 src_top_row++;
0485 dst_row++;
0486 }
0487 while (dst_row < dst_rows) {
0488 char32_t *dst_line = dst->lines[dst_row];
0489
0490 memset32(dst_line, ' ', dst_cols);
0491 dst_row++;
0492 }
0493 }
0494
0495
0496
0497
0498
0499
0500
0501 int vc_uniscr_check(struct vc_data *vc)
0502 {
0503 struct uni_screen *uniscr;
0504 unsigned short *p;
0505 int x, y, mask;
0506
0507 if (__is_defined(NO_VC_UNI_SCREEN))
0508 return -EOPNOTSUPP;
0509
0510 WARN_CONSOLE_UNLOCKED();
0511
0512 if (!vc->vc_utf)
0513 return -ENODATA;
0514
0515 if (vc->vc_uni_screen)
0516 return 0;
0517
0518 uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows);
0519 if (!uniscr)
0520 return -ENOMEM;
0521
0522
0523
0524
0525
0526
0527
0528 p = (unsigned short *)vc->vc_origin;
0529 mask = vc->vc_hi_font_mask | 0xff;
0530 for (y = 0; y < vc->vc_rows; y++) {
0531 char32_t *line = uniscr->lines[y];
0532 for (x = 0; x < vc->vc_cols; x++) {
0533 u16 glyph = scr_readw(p++) & mask;
0534 line[x] = inverse_translate(vc, glyph, true);
0535 }
0536 }
0537
0538 vc->vc_uni_screen = uniscr;
0539 return 0;
0540 }
0541
0542
0543
0544
0545
0546
0547 void vc_uniscr_copy_line(const struct vc_data *vc, void *dest, bool viewed,
0548 unsigned int row, unsigned int col, unsigned int nr)
0549 {
0550 struct uni_screen *uniscr = get_vc_uniscr(vc);
0551 int offset = row * vc->vc_size_row + col * 2;
0552 unsigned long pos;
0553
0554 BUG_ON(!uniscr);
0555
0556 pos = (unsigned long)screenpos(vc, offset, viewed);
0557 if (pos >= vc->vc_origin && pos < vc->vc_scr_end) {
0558
0559
0560
0561
0562
0563 row = (pos - vc->vc_origin) / vc->vc_size_row;
0564 col = ((pos - vc->vc_origin) % vc->vc_size_row) / 2;
0565 memcpy(dest, &uniscr->lines[row][col], nr * sizeof(char32_t));
0566 } else {
0567
0568
0569
0570
0571
0572
0573 u16 *p = (u16 *)pos;
0574 int mask = vc->vc_hi_font_mask | 0xff;
0575 char32_t *uni_buf = dest;
0576 while (nr--) {
0577 u16 glyph = scr_readw(p++) & mask;
0578 *uni_buf++ = inverse_translate(vc, glyph, true);
0579 }
0580 }
0581 }
0582
0583
0584 static void vc_uniscr_debug_check(struct vc_data *vc)
0585 {
0586 struct uni_screen *uniscr = get_vc_uniscr(vc);
0587 unsigned short *p;
0588 int x, y, mask;
0589
0590 if (!VC_UNI_SCREEN_DEBUG || !uniscr)
0591 return;
0592
0593 WARN_CONSOLE_UNLOCKED();
0594
0595
0596
0597
0598
0599 p = (unsigned short *)vc->vc_origin;
0600 mask = vc->vc_hi_font_mask | 0xff;
0601 for (y = 0; y < vc->vc_rows; y++) {
0602 char32_t *line = uniscr->lines[y];
0603 for (x = 0; x < vc->vc_cols; x++) {
0604 u16 glyph = scr_readw(p++) & mask;
0605 char32_t uc = line[x];
0606 int tc = conv_uni_to_pc(vc, uc);
0607 if (tc == -4)
0608 tc = conv_uni_to_pc(vc, 0xfffd);
0609 if (tc == -4)
0610 tc = conv_uni_to_pc(vc, '?');
0611 if (tc != glyph)
0612 pr_err_ratelimited(
0613 "%s: mismatch at %d,%d: glyph=%#x tc=%#x\n",
0614 __func__, x, y, glyph, tc);
0615 }
0616 }
0617 }
0618
0619
0620 static void con_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
0621 enum con_scroll dir, unsigned int nr)
0622 {
0623 u16 *clear, *d, *s;
0624
0625 if (t + nr >= b)
0626 nr = b - t - 1;
0627 if (b > vc->vc_rows || t >= b || nr < 1)
0628 return;
0629 vc_uniscr_scroll(vc, t, b, dir, nr);
0630 if (con_is_visible(vc) && vc->vc_sw->con_scroll(vc, t, b, dir, nr))
0631 return;
0632
0633 s = clear = (u16 *)(vc->vc_origin + vc->vc_size_row * t);
0634 d = (u16 *)(vc->vc_origin + vc->vc_size_row * (t + nr));
0635
0636 if (dir == SM_UP) {
0637 clear = s + (b - t - nr) * vc->vc_cols;
0638 swap(s, d);
0639 }
0640 scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
0641 scr_memsetw(clear, vc->vc_video_erase_char, vc->vc_size_row * nr);
0642 }
0643
0644 static void do_update_region(struct vc_data *vc, unsigned long start, int count)
0645 {
0646 unsigned int xx, yy, offset;
0647 u16 *p;
0648
0649 p = (u16 *) start;
0650 if (!vc->vc_sw->con_getxy) {
0651 offset = (start - vc->vc_origin) / 2;
0652 xx = offset % vc->vc_cols;
0653 yy = offset / vc->vc_cols;
0654 } else {
0655 int nxx, nyy;
0656 start = vc->vc_sw->con_getxy(vc, start, &nxx, &nyy);
0657 xx = nxx; yy = nyy;
0658 }
0659 for(;;) {
0660 u16 attrib = scr_readw(p) & 0xff00;
0661 int startx = xx;
0662 u16 *q = p;
0663 while (xx < vc->vc_cols && count) {
0664 if (attrib != (scr_readw(p) & 0xff00)) {
0665 if (p > q)
0666 vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
0667 startx = xx;
0668 q = p;
0669 attrib = scr_readw(p) & 0xff00;
0670 }
0671 p++;
0672 xx++;
0673 count--;
0674 }
0675 if (p > q)
0676 vc->vc_sw->con_putcs(vc, q, p-q, yy, startx);
0677 if (!count)
0678 break;
0679 xx = 0;
0680 yy++;
0681 if (vc->vc_sw->con_getxy) {
0682 p = (u16 *)start;
0683 start = vc->vc_sw->con_getxy(vc, start, NULL, NULL);
0684 }
0685 }
0686 }
0687
0688 void update_region(struct vc_data *vc, unsigned long start, int count)
0689 {
0690 WARN_CONSOLE_UNLOCKED();
0691
0692 if (con_should_update(vc)) {
0693 hide_cursor(vc);
0694 do_update_region(vc, start, count);
0695 set_cursor(vc);
0696 }
0697 }
0698
0699
0700
0701 static u8 build_attr(struct vc_data *vc, u8 _color,
0702 enum vc_intensity _intensity, bool _blink, bool _underline,
0703 bool _reverse, bool _italic)
0704 {
0705 if (vc->vc_sw->con_build_attr)
0706 return vc->vc_sw->con_build_attr(vc, _color, _intensity,
0707 _blink, _underline, _reverse, _italic);
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719 {
0720 u8 a = _color;
0721 if (!vc->vc_can_do_color)
0722 return _intensity |
0723 (_italic << 1) |
0724 (_underline << 2) |
0725 (_reverse << 3) |
0726 (_blink << 7);
0727 if (_italic)
0728 a = (a & 0xF0) | vc->vc_itcolor;
0729 else if (_underline)
0730 a = (a & 0xf0) | vc->vc_ulcolor;
0731 else if (_intensity == VCI_HALF_BRIGHT)
0732 a = (a & 0xf0) | vc->vc_halfcolor;
0733 if (_reverse)
0734 a = (a & 0x88) | (((a >> 4) | (a << 4)) & 0x77);
0735 if (_blink)
0736 a ^= 0x80;
0737 if (_intensity == VCI_BOLD)
0738 a ^= 0x08;
0739 if (vc->vc_hi_font_mask == 0x100)
0740 a <<= 1;
0741 return a;
0742 }
0743 }
0744
0745 static void update_attr(struct vc_data *vc)
0746 {
0747 vc->vc_attr = build_attr(vc, vc->state.color, vc->state.intensity,
0748 vc->state.blink, vc->state.underline,
0749 vc->state.reverse ^ vc->vc_decscnm, vc->state.italic);
0750 vc->vc_video_erase_char = ' ' | (build_attr(vc, vc->state.color,
0751 VCI_NORMAL, vc->state.blink, false,
0752 vc->vc_decscnm, false) << 8);
0753 }
0754
0755
0756 void invert_screen(struct vc_data *vc, int offset, int count, bool viewed)
0757 {
0758 unsigned short *p;
0759
0760 WARN_CONSOLE_UNLOCKED();
0761
0762 count /= 2;
0763 p = screenpos(vc, offset, viewed);
0764 if (vc->vc_sw->con_invert_region) {
0765 vc->vc_sw->con_invert_region(vc, p, count);
0766 } else {
0767 u16 *q = p;
0768 int cnt = count;
0769 u16 a;
0770
0771 if (!vc->vc_can_do_color) {
0772 while (cnt--) {
0773 a = scr_readw(q);
0774 a ^= 0x0800;
0775 scr_writew(a, q);
0776 q++;
0777 }
0778 } else if (vc->vc_hi_font_mask == 0x100) {
0779 while (cnt--) {
0780 a = scr_readw(q);
0781 a = (a & 0x11ff) |
0782 ((a & 0xe000) >> 4) |
0783 ((a & 0x0e00) << 4);
0784 scr_writew(a, q);
0785 q++;
0786 }
0787 } else {
0788 while (cnt--) {
0789 a = scr_readw(q);
0790 a = (a & 0x88ff) |
0791 ((a & 0x7000) >> 4) |
0792 ((a & 0x0700) << 4);
0793 scr_writew(a, q);
0794 q++;
0795 }
0796 }
0797 }
0798
0799 if (con_should_update(vc))
0800 do_update_region(vc, (unsigned long) p, count);
0801 notify_update(vc);
0802 }
0803
0804
0805 void complement_pos(struct vc_data *vc, int offset)
0806 {
0807 static int old_offset = -1;
0808 static unsigned short old;
0809 static unsigned short oldx, oldy;
0810
0811 WARN_CONSOLE_UNLOCKED();
0812
0813 if (old_offset != -1 && old_offset >= 0 &&
0814 old_offset < vc->vc_screenbuf_size) {
0815 scr_writew(old, screenpos(vc, old_offset, true));
0816 if (con_should_update(vc))
0817 vc->vc_sw->con_putc(vc, old, oldy, oldx);
0818 notify_update(vc);
0819 }
0820
0821 old_offset = offset;
0822
0823 if (offset != -1 && offset >= 0 &&
0824 offset < vc->vc_screenbuf_size) {
0825 unsigned short new;
0826 unsigned short *p;
0827 p = screenpos(vc, offset, true);
0828 old = scr_readw(p);
0829 new = old ^ vc->vc_complement_mask;
0830 scr_writew(new, p);
0831 if (con_should_update(vc)) {
0832 oldx = (offset >> 1) % vc->vc_cols;
0833 oldy = (offset >> 1) / vc->vc_cols;
0834 vc->vc_sw->con_putc(vc, new, oldy, oldx);
0835 }
0836 notify_update(vc);
0837 }
0838 }
0839
0840 static void insert_char(struct vc_data *vc, unsigned int nr)
0841 {
0842 unsigned short *p = (unsigned short *) vc->vc_pos;
0843
0844 vc_uniscr_insert(vc, nr);
0845 scr_memmovew(p + nr, p, (vc->vc_cols - vc->state.x - nr) * 2);
0846 scr_memsetw(p, vc->vc_video_erase_char, nr * 2);
0847 vc->vc_need_wrap = 0;
0848 if (con_should_update(vc))
0849 do_update_region(vc, (unsigned long) p,
0850 vc->vc_cols - vc->state.x);
0851 }
0852
0853 static void delete_char(struct vc_data *vc, unsigned int nr)
0854 {
0855 unsigned short *p = (unsigned short *) vc->vc_pos;
0856
0857 vc_uniscr_delete(vc, nr);
0858 scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
0859 scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
0860 nr * 2);
0861 vc->vc_need_wrap = 0;
0862 if (con_should_update(vc))
0863 do_update_region(vc, (unsigned long) p,
0864 vc->vc_cols - vc->state.x);
0865 }
0866
0867 static int softcursor_original = -1;
0868
0869 static void add_softcursor(struct vc_data *vc)
0870 {
0871 int i = scr_readw((u16 *) vc->vc_pos);
0872 u32 type = vc->vc_cursor_type;
0873
0874 if (!(type & CUR_SW))
0875 return;
0876 if (softcursor_original != -1)
0877 return;
0878 softcursor_original = i;
0879 i |= CUR_SET(type);
0880 i ^= CUR_CHANGE(type);
0881 if ((type & CUR_ALWAYS_BG) &&
0882 (softcursor_original & CUR_BG) == (i & CUR_BG))
0883 i ^= CUR_BG;
0884 if ((type & CUR_INVERT_FG_BG) && (i & CUR_FG) == ((i & CUR_BG) >> 4))
0885 i ^= CUR_FG;
0886 scr_writew(i, (u16 *)vc->vc_pos);
0887 if (con_should_update(vc))
0888 vc->vc_sw->con_putc(vc, i, vc->state.y, vc->state.x);
0889 }
0890
0891 static void hide_softcursor(struct vc_data *vc)
0892 {
0893 if (softcursor_original != -1) {
0894 scr_writew(softcursor_original, (u16 *)vc->vc_pos);
0895 if (con_should_update(vc))
0896 vc->vc_sw->con_putc(vc, softcursor_original,
0897 vc->state.y, vc->state.x);
0898 softcursor_original = -1;
0899 }
0900 }
0901
0902 static void hide_cursor(struct vc_data *vc)
0903 {
0904 if (vc_is_sel(vc))
0905 clear_selection();
0906
0907 vc->vc_sw->con_cursor(vc, CM_ERASE);
0908 hide_softcursor(vc);
0909 }
0910
0911 static void set_cursor(struct vc_data *vc)
0912 {
0913 if (!con_is_fg(vc) || console_blanked || vc->vc_mode == KD_GRAPHICS)
0914 return;
0915 if (vc->vc_deccm) {
0916 if (vc_is_sel(vc))
0917 clear_selection();
0918 add_softcursor(vc);
0919 if (CUR_SIZE(vc->vc_cursor_type) != CUR_NONE)
0920 vc->vc_sw->con_cursor(vc, CM_DRAW);
0921 } else
0922 hide_cursor(vc);
0923 }
0924
0925 static void set_origin(struct vc_data *vc)
0926 {
0927 WARN_CONSOLE_UNLOCKED();
0928
0929 if (!con_is_visible(vc) ||
0930 !vc->vc_sw->con_set_origin ||
0931 !vc->vc_sw->con_set_origin(vc))
0932 vc->vc_origin = (unsigned long)vc->vc_screenbuf;
0933 vc->vc_visible_origin = vc->vc_origin;
0934 vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
0935 vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->state.y +
0936 2 * vc->state.x;
0937 }
0938
0939 static void save_screen(struct vc_data *vc)
0940 {
0941 WARN_CONSOLE_UNLOCKED();
0942
0943 if (vc->vc_sw->con_save_screen)
0944 vc->vc_sw->con_save_screen(vc);
0945 }
0946
0947 static void flush_scrollback(struct vc_data *vc)
0948 {
0949 WARN_CONSOLE_UNLOCKED();
0950
0951 set_origin(vc);
0952 if (vc->vc_sw->con_flush_scrollback) {
0953 vc->vc_sw->con_flush_scrollback(vc);
0954 } else if (con_is_visible(vc)) {
0955
0956
0957
0958
0959
0960
0961
0962
0963 hide_cursor(vc);
0964 vc->vc_sw->con_switch(vc);
0965 set_cursor(vc);
0966 }
0967 }
0968
0969
0970
0971
0972
0973 void clear_buffer_attributes(struct vc_data *vc)
0974 {
0975 unsigned short *p = (unsigned short *)vc->vc_origin;
0976 int count = vc->vc_screenbuf_size / 2;
0977 int mask = vc->vc_hi_font_mask | 0xff;
0978
0979 for (; count > 0; count--, p++) {
0980 scr_writew((scr_readw(p)&mask) | (vc->vc_video_erase_char & ~mask), p);
0981 }
0982 }
0983
0984 void redraw_screen(struct vc_data *vc, int is_switch)
0985 {
0986 int redraw = 0;
0987
0988 WARN_CONSOLE_UNLOCKED();
0989
0990 if (!vc) {
0991
0992
0993 return;
0994 }
0995
0996 if (is_switch) {
0997 struct vc_data *old_vc = vc_cons[fg_console].d;
0998 if (old_vc == vc)
0999 return;
1000 if (!con_is_visible(vc))
1001 redraw = 1;
1002 *vc->vc_display_fg = vc;
1003 fg_console = vc->vc_num;
1004 hide_cursor(old_vc);
1005 if (!con_is_visible(old_vc)) {
1006 save_screen(old_vc);
1007 set_origin(old_vc);
1008 }
1009 if (tty0dev)
1010 sysfs_notify(&tty0dev->kobj, NULL, "active");
1011 } else {
1012 hide_cursor(vc);
1013 redraw = 1;
1014 }
1015
1016 if (redraw) {
1017 int update;
1018 int old_was_color = vc->vc_can_do_color;
1019
1020 set_origin(vc);
1021 update = vc->vc_sw->con_switch(vc);
1022 set_palette(vc);
1023
1024
1025
1026
1027
1028
1029 if (old_was_color != vc->vc_can_do_color) {
1030 update_attr(vc);
1031 clear_buffer_attributes(vc);
1032 }
1033
1034 if (update && vc->vc_mode != KD_GRAPHICS)
1035 do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
1036 }
1037 set_cursor(vc);
1038 if (is_switch) {
1039 vt_set_leds_compute_shiftstate();
1040 notify_update(vc);
1041 }
1042 }
1043
1044
1045
1046
1047
1048 int vc_cons_allocated(unsigned int i)
1049 {
1050 return (i < MAX_NR_CONSOLES && vc_cons[i].d);
1051 }
1052
1053 static void visual_init(struct vc_data *vc, int num, int init)
1054 {
1055
1056 if (vc->vc_sw)
1057 module_put(vc->vc_sw->owner);
1058 vc->vc_sw = conswitchp;
1059 #ifndef VT_SINGLE_DRIVER
1060 if (con_driver_map[num])
1061 vc->vc_sw = con_driver_map[num];
1062 #endif
1063 __module_get(vc->vc_sw->owner);
1064 vc->vc_num = num;
1065 vc->vc_display_fg = &master_display_fg;
1066 if (vc->uni_pagedict_loc)
1067 con_free_unimap(vc);
1068 vc->uni_pagedict_loc = &vc->uni_pagedict;
1069 vc->uni_pagedict = NULL;
1070 vc->vc_hi_font_mask = 0;
1071 vc->vc_complement_mask = 0;
1072 vc->vc_can_do_color = 0;
1073 vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
1074 vc->vc_sw->con_init(vc, init);
1075 if (!vc->vc_complement_mask)
1076 vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
1077 vc->vc_s_complement_mask = vc->vc_complement_mask;
1078 vc->vc_size_row = vc->vc_cols << 1;
1079 vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
1080 }
1081
1082
1083 static void visual_deinit(struct vc_data *vc)
1084 {
1085 vc->vc_sw->con_deinit(vc);
1086 module_put(vc->vc_sw->owner);
1087 }
1088
1089 static void vc_port_destruct(struct tty_port *port)
1090 {
1091 struct vc_data *vc = container_of(port, struct vc_data, port);
1092
1093 kfree(vc);
1094 }
1095
1096 static const struct tty_port_operations vc_port_ops = {
1097 .destruct = vc_port_destruct,
1098 };
1099
1100
1101
1102
1103
1104
1105 #define VC_MAXCOL (32767)
1106 #define VC_MAXROW (32767)
1107
1108 int vc_allocate(unsigned int currcons)
1109 {
1110 struct vt_notifier_param param;
1111 struct vc_data *vc;
1112 int err;
1113
1114 WARN_CONSOLE_UNLOCKED();
1115
1116 if (currcons >= MAX_NR_CONSOLES)
1117 return -ENXIO;
1118
1119 if (vc_cons[currcons].d)
1120 return 0;
1121
1122
1123
1124
1125
1126
1127
1128 param.vc = vc = kzalloc(sizeof(struct vc_data), GFP_KERNEL);
1129 if (!vc)
1130 return -ENOMEM;
1131
1132 vc_cons[currcons].d = vc;
1133 tty_port_init(&vc->port);
1134 vc->port.ops = &vc_port_ops;
1135 INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
1136
1137 visual_init(vc, currcons, 1);
1138
1139 if (!*vc->uni_pagedict_loc)
1140 con_set_default_unimap(vc);
1141
1142 err = -EINVAL;
1143 if (vc->vc_cols > VC_MAXCOL || vc->vc_rows > VC_MAXROW ||
1144 vc->vc_screenbuf_size > KMALLOC_MAX_SIZE || !vc->vc_screenbuf_size)
1145 goto err_free;
1146 err = -ENOMEM;
1147 vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_KERNEL);
1148 if (!vc->vc_screenbuf)
1149 goto err_free;
1150
1151
1152
1153 if (global_cursor_default == -1)
1154 global_cursor_default = 1;
1155
1156 vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
1157 vcs_make_sysfs(currcons);
1158 atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, ¶m);
1159
1160 return 0;
1161 err_free:
1162 visual_deinit(vc);
1163 kfree(vc);
1164 vc_cons[currcons].d = NULL;
1165 return err;
1166 }
1167
1168 static inline int resize_screen(struct vc_data *vc, int width, int height,
1169 int user)
1170 {
1171
1172 int err = 0;
1173
1174 if (vc->vc_sw->con_resize)
1175 err = vc->vc_sw->con_resize(vc, width, height, user);
1176
1177 return err;
1178 }
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195 static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
1196 unsigned int cols, unsigned int lines)
1197 {
1198 unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
1199 unsigned long end;
1200 unsigned int old_rows, old_row_size, first_copied_row;
1201 unsigned int new_cols, new_rows, new_row_size, new_screen_size;
1202 unsigned int user;
1203 unsigned short *oldscreen, *newscreen;
1204 struct uni_screen *new_uniscr = NULL;
1205
1206 WARN_CONSOLE_UNLOCKED();
1207
1208 if (!vc)
1209 return -ENXIO;
1210
1211 user = vc->vc_resize_user;
1212 vc->vc_resize_user = 0;
1213
1214 if (cols > VC_MAXCOL || lines > VC_MAXROW)
1215 return -EINVAL;
1216
1217 new_cols = (cols ? cols : vc->vc_cols);
1218 new_rows = (lines ? lines : vc->vc_rows);
1219 new_row_size = new_cols << 1;
1220 new_screen_size = new_row_size * new_rows;
1221
1222 if (new_cols == vc->vc_cols && new_rows == vc->vc_rows) {
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239 return resize_screen(vc, new_cols, new_rows, user);
1240 }
1241
1242 if (new_screen_size > KMALLOC_MAX_SIZE || !new_screen_size)
1243 return -EINVAL;
1244 newscreen = kzalloc(new_screen_size, GFP_USER);
1245 if (!newscreen)
1246 return -ENOMEM;
1247
1248 if (get_vc_uniscr(vc)) {
1249 new_uniscr = vc_uniscr_alloc(new_cols, new_rows);
1250 if (!new_uniscr) {
1251 kfree(newscreen);
1252 return -ENOMEM;
1253 }
1254 }
1255
1256 if (vc_is_sel(vc))
1257 clear_selection();
1258
1259 old_rows = vc->vc_rows;
1260 old_row_size = vc->vc_size_row;
1261
1262 err = resize_screen(vc, new_cols, new_rows, user);
1263 if (err) {
1264 kfree(newscreen);
1265 vc_uniscr_free(new_uniscr);
1266 return err;
1267 }
1268
1269 vc->vc_rows = new_rows;
1270 vc->vc_cols = new_cols;
1271 vc->vc_size_row = new_row_size;
1272 vc->vc_screenbuf_size = new_screen_size;
1273
1274 rlth = min(old_row_size, new_row_size);
1275 rrem = new_row_size - rlth;
1276 old_origin = vc->vc_origin;
1277 new_origin = (long) newscreen;
1278 new_scr_end = new_origin + new_screen_size;
1279
1280 if (vc->state.y > new_rows) {
1281 if (old_rows - vc->state.y < new_rows) {
1282
1283
1284
1285
1286 first_copied_row = (old_rows - new_rows);
1287 } else {
1288
1289
1290
1291
1292 first_copied_row = (vc->state.y - new_rows/2);
1293 }
1294 old_origin += first_copied_row * old_row_size;
1295 } else
1296 first_copied_row = 0;
1297 end = old_origin + old_row_size * min(old_rows, new_rows);
1298
1299 vc_uniscr_copy_area(new_uniscr, new_cols, new_rows,
1300 get_vc_uniscr(vc), rlth/2, first_copied_row,
1301 min(old_rows, new_rows));
1302 vc_uniscr_set(vc, new_uniscr);
1303
1304 update_attr(vc);
1305
1306 while (old_origin < end) {
1307 scr_memcpyw((unsigned short *) new_origin,
1308 (unsigned short *) old_origin, rlth);
1309 if (rrem)
1310 scr_memsetw((void *)(new_origin + rlth),
1311 vc->vc_video_erase_char, rrem);
1312 old_origin += old_row_size;
1313 new_origin += new_row_size;
1314 }
1315 if (new_scr_end > new_origin)
1316 scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
1317 new_scr_end - new_origin);
1318 oldscreen = vc->vc_screenbuf;
1319 vc->vc_screenbuf = newscreen;
1320 vc->vc_screenbuf_size = new_screen_size;
1321 set_origin(vc);
1322 kfree(oldscreen);
1323
1324
1325 vc->vc_top = 0;
1326 vc->vc_bottom = vc->vc_rows;
1327 gotoxy(vc, vc->state.x, vc->state.y);
1328 save_cur(vc);
1329
1330 if (tty) {
1331
1332
1333 struct winsize ws;
1334 memset(&ws, 0, sizeof(ws));
1335 ws.ws_row = vc->vc_rows;
1336 ws.ws_col = vc->vc_cols;
1337 ws.ws_ypixel = vc->vc_scan_lines;
1338 tty_do_resize(tty, &ws);
1339 }
1340
1341 if (con_is_visible(vc))
1342 update_screen(vc);
1343 vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
1344 notify_update(vc);
1345 return err;
1346 }
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360 int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
1361 {
1362 return vc_do_resize(vc->port.tty, vc, cols, rows);
1363 }
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377 static int vt_resize(struct tty_struct *tty, struct winsize *ws)
1378 {
1379 struct vc_data *vc = tty->driver_data;
1380 int ret;
1381
1382 console_lock();
1383 ret = vc_do_resize(tty, vc, ws->ws_col, ws->ws_row);
1384 console_unlock();
1385 return ret;
1386 }
1387
1388 struct vc_data *vc_deallocate(unsigned int currcons)
1389 {
1390 struct vc_data *vc = NULL;
1391
1392 WARN_CONSOLE_UNLOCKED();
1393
1394 if (vc_cons_allocated(currcons)) {
1395 struct vt_notifier_param param;
1396
1397 param.vc = vc = vc_cons[currcons].d;
1398 atomic_notifier_call_chain(&vt_notifier_list, VT_DEALLOCATE, ¶m);
1399 vcs_remove_sysfs(currcons);
1400 visual_deinit(vc);
1401 con_free_unimap(vc);
1402 put_pid(vc->vt_pid);
1403 vc_uniscr_set(vc, NULL);
1404 kfree(vc->vc_screenbuf);
1405 vc_cons[currcons].d = NULL;
1406 }
1407 return vc;
1408 }
1409
1410
1411
1412
1413
1414 enum { EPecma = 0, EPdec, EPeq, EPgt, EPlt};
1415
1416 #define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x))
1417 #define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x))
1418 #define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x))
1419
1420 #define decarm VC_REPEAT
1421 #define decckm VC_CKMODE
1422 #define kbdapplic VC_APPLIC
1423 #define lnm VC_CRLF
1424
1425 const unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
1426 8,12,10,14, 9,13,11,15 };
1427
1428
1429 unsigned char default_red[] = {
1430 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa,
1431 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff
1432 };
1433 module_param_array(default_red, byte, NULL, S_IRUGO | S_IWUSR);
1434
1435 unsigned char default_grn[] = {
1436 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa,
1437 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff
1438 };
1439 module_param_array(default_grn, byte, NULL, S_IRUGO | S_IWUSR);
1440
1441 unsigned char default_blu[] = {
1442 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa,
1443 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff
1444 };
1445 module_param_array(default_blu, byte, NULL, S_IRUGO | S_IWUSR);
1446
1447
1448
1449
1450
1451
1452 static void gotoxy(struct vc_data *vc, int new_x, int new_y)
1453 {
1454 int min_y, max_y;
1455
1456 if (new_x < 0)
1457 vc->state.x = 0;
1458 else {
1459 if (new_x >= vc->vc_cols)
1460 vc->state.x = vc->vc_cols - 1;
1461 else
1462 vc->state.x = new_x;
1463 }
1464
1465 if (vc->vc_decom) {
1466 min_y = vc->vc_top;
1467 max_y = vc->vc_bottom;
1468 } else {
1469 min_y = 0;
1470 max_y = vc->vc_rows;
1471 }
1472 if (new_y < min_y)
1473 vc->state.y = min_y;
1474 else if (new_y >= max_y)
1475 vc->state.y = max_y - 1;
1476 else
1477 vc->state.y = new_y;
1478 vc->vc_pos = vc->vc_origin + vc->state.y * vc->vc_size_row +
1479 (vc->state.x << 1);
1480 vc->vc_need_wrap = 0;
1481 }
1482
1483
1484 static void gotoxay(struct vc_data *vc, int new_x, int new_y)
1485 {
1486 gotoxy(vc, new_x, vc->vc_decom ? (vc->vc_top + new_y) : new_y);
1487 }
1488
1489 void scrollback(struct vc_data *vc)
1490 {
1491 scrolldelta(-(vc->vc_rows / 2));
1492 }
1493
1494 void scrollfront(struct vc_data *vc, int lines)
1495 {
1496 if (!lines)
1497 lines = vc->vc_rows / 2;
1498 scrolldelta(lines);
1499 }
1500
1501 static void lf(struct vc_data *vc)
1502 {
1503
1504
1505
1506 if (vc->state.y + 1 == vc->vc_bottom)
1507 con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_UP, 1);
1508 else if (vc->state.y < vc->vc_rows - 1) {
1509 vc->state.y++;
1510 vc->vc_pos += vc->vc_size_row;
1511 }
1512 vc->vc_need_wrap = 0;
1513 notify_write(vc, '\n');
1514 }
1515
1516 static void ri(struct vc_data *vc)
1517 {
1518
1519
1520
1521 if (vc->state.y == vc->vc_top)
1522 con_scroll(vc, vc->vc_top, vc->vc_bottom, SM_DOWN, 1);
1523 else if (vc->state.y > 0) {
1524 vc->state.y--;
1525 vc->vc_pos -= vc->vc_size_row;
1526 }
1527 vc->vc_need_wrap = 0;
1528 }
1529
1530 static inline void cr(struct vc_data *vc)
1531 {
1532 vc->vc_pos -= vc->state.x << 1;
1533 vc->vc_need_wrap = vc->state.x = 0;
1534 notify_write(vc, '\r');
1535 }
1536
1537 static inline void bs(struct vc_data *vc)
1538 {
1539 if (vc->state.x) {
1540 vc->vc_pos -= 2;
1541 vc->state.x--;
1542 vc->vc_need_wrap = 0;
1543 notify_write(vc, '\b');
1544 }
1545 }
1546
1547 static inline void del(struct vc_data *vc)
1548 {
1549
1550 }
1551
1552 static void csi_J(struct vc_data *vc, int vpar)
1553 {
1554 unsigned int count;
1555 unsigned short * start;
1556
1557 switch (vpar) {
1558 case 0:
1559 vc_uniscr_clear_line(vc, vc->state.x,
1560 vc->vc_cols - vc->state.x);
1561 vc_uniscr_clear_lines(vc, vc->state.y + 1,
1562 vc->vc_rows - vc->state.y - 1);
1563 count = (vc->vc_scr_end - vc->vc_pos) >> 1;
1564 start = (unsigned short *)vc->vc_pos;
1565 break;
1566 case 1:
1567 vc_uniscr_clear_line(vc, 0, vc->state.x + 1);
1568 vc_uniscr_clear_lines(vc, 0, vc->state.y);
1569 count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1;
1570 start = (unsigned short *)vc->vc_origin;
1571 break;
1572 case 3:
1573 flush_scrollback(vc);
1574 fallthrough;
1575 case 2:
1576 vc_uniscr_clear_lines(vc, 0, vc->vc_rows);
1577 count = vc->vc_cols * vc->vc_rows;
1578 start = (unsigned short *)vc->vc_origin;
1579 break;
1580 default:
1581 return;
1582 }
1583 scr_memsetw(start, vc->vc_video_erase_char, 2 * count);
1584 if (con_should_update(vc))
1585 do_update_region(vc, (unsigned long) start, count);
1586 vc->vc_need_wrap = 0;
1587 }
1588
1589 static void csi_K(struct vc_data *vc, int vpar)
1590 {
1591 unsigned int count;
1592 unsigned short *start = (unsigned short *)vc->vc_pos;
1593 int offset;
1594
1595 switch (vpar) {
1596 case 0:
1597 offset = 0;
1598 count = vc->vc_cols - vc->state.x;
1599 break;
1600 case 1:
1601 offset = -vc->state.x;
1602 count = vc->state.x + 1;
1603 break;
1604 case 2:
1605 offset = -vc->state.x;
1606 count = vc->vc_cols;
1607 break;
1608 default:
1609 return;
1610 }
1611 vc_uniscr_clear_line(vc, vc->state.x + offset, count);
1612 scr_memsetw(start + offset, vc->vc_video_erase_char, 2 * count);
1613 vc->vc_need_wrap = 0;
1614 if (con_should_update(vc))
1615 do_update_region(vc, (unsigned long)(start + offset), count);
1616 }
1617
1618
1619 static void csi_X(struct vc_data *vc, unsigned int vpar)
1620 {
1621 unsigned int count;
1622
1623 if (!vpar)
1624 vpar++;
1625
1626 count = min(vpar, vc->vc_cols - vc->state.x);
1627
1628 vc_uniscr_clear_line(vc, vc->state.x, count);
1629 scr_memsetw((unsigned short *)vc->vc_pos, vc->vc_video_erase_char, 2 * count);
1630 if (con_should_update(vc))
1631 vc->vc_sw->con_clear(vc, vc->state.y, vc->state.x, 1, count);
1632 vc->vc_need_wrap = 0;
1633 }
1634
1635 static void default_attr(struct vc_data *vc)
1636 {
1637 vc->state.intensity = VCI_NORMAL;
1638 vc->state.italic = false;
1639 vc->state.underline = false;
1640 vc->state.reverse = false;
1641 vc->state.blink = false;
1642 vc->state.color = vc->vc_def_color;
1643 }
1644
1645 struct rgb { u8 r; u8 g; u8 b; };
1646
1647 static void rgb_from_256(int i, struct rgb *c)
1648 {
1649 if (i < 8) {
1650 c->r = i&1 ? 0xaa : 0x00;
1651 c->g = i&2 ? 0xaa : 0x00;
1652 c->b = i&4 ? 0xaa : 0x00;
1653 } else if (i < 16) {
1654 c->r = i&1 ? 0xff : 0x55;
1655 c->g = i&2 ? 0xff : 0x55;
1656 c->b = i&4 ? 0xff : 0x55;
1657 } else if (i < 232) {
1658 c->r = (i - 16) / 36 * 85 / 2;
1659 c->g = (i - 16) / 6 % 6 * 85 / 2;
1660 c->b = (i - 16) % 6 * 85 / 2;
1661 } else
1662 c->r = c->g = c->b = i * 10 - 2312;
1663 }
1664
1665 static void rgb_foreground(struct vc_data *vc, const struct rgb *c)
1666 {
1667 u8 hue = 0, max = max3(c->r, c->g, c->b);
1668
1669 if (c->r > max / 2)
1670 hue |= 4;
1671 if (c->g > max / 2)
1672 hue |= 2;
1673 if (c->b > max / 2)
1674 hue |= 1;
1675
1676 if (hue == 7 && max <= 0x55) {
1677 hue = 0;
1678 vc->state.intensity = VCI_BOLD;
1679 } else if (max > 0xaa)
1680 vc->state.intensity = VCI_BOLD;
1681 else
1682 vc->state.intensity = VCI_NORMAL;
1683
1684 vc->state.color = (vc->state.color & 0xf0) | hue;
1685 }
1686
1687 static void rgb_background(struct vc_data *vc, const struct rgb *c)
1688 {
1689
1690 vc->state.color = (vc->state.color & 0x0f)
1691 | (c->r&0x80) >> 1 | (c->g&0x80) >> 2 | (c->b&0x80) >> 3;
1692 }
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703 static int vc_t416_color(struct vc_data *vc, int i,
1704 void(*set_color)(struct vc_data *vc, const struct rgb *c))
1705 {
1706 struct rgb c;
1707
1708 i++;
1709 if (i > vc->vc_npar)
1710 return i;
1711
1712 if (vc->vc_par[i] == 5 && i + 1 <= vc->vc_npar) {
1713
1714 i++;
1715 rgb_from_256(vc->vc_par[i], &c);
1716 } else if (vc->vc_par[i] == 2 && i + 3 <= vc->vc_npar) {
1717
1718 c.r = vc->vc_par[i + 1];
1719 c.g = vc->vc_par[i + 2];
1720 c.b = vc->vc_par[i + 3];
1721 i += 3;
1722 } else
1723 return i;
1724
1725 set_color(vc, &c);
1726
1727 return i;
1728 }
1729
1730
1731 static void csi_m(struct vc_data *vc)
1732 {
1733 int i;
1734
1735 for (i = 0; i <= vc->vc_npar; i++)
1736 switch (vc->vc_par[i]) {
1737 case 0:
1738 default_attr(vc);
1739 break;
1740 case 1:
1741 vc->state.intensity = VCI_BOLD;
1742 break;
1743 case 2:
1744 vc->state.intensity = VCI_HALF_BRIGHT;
1745 break;
1746 case 3:
1747 vc->state.italic = true;
1748 break;
1749 case 21:
1750
1751
1752
1753
1754 case 4:
1755 vc->state.underline = true;
1756 break;
1757 case 5:
1758 vc->state.blink = true;
1759 break;
1760 case 7:
1761 vc->state.reverse = true;
1762 break;
1763 case 10:
1764
1765
1766
1767 vc->vc_translate = set_translate(vc->state.Gx_charset[vc->state.charset], vc);
1768 vc->vc_disp_ctrl = 0;
1769 vc->vc_toggle_meta = 0;
1770 break;
1771 case 11:
1772
1773
1774
1775 vc->vc_translate = set_translate(IBMPC_MAP, vc);
1776 vc->vc_disp_ctrl = 1;
1777 vc->vc_toggle_meta = 0;
1778 break;
1779 case 12:
1780
1781
1782
1783 vc->vc_translate = set_translate(IBMPC_MAP, vc);
1784 vc->vc_disp_ctrl = 1;
1785 vc->vc_toggle_meta = 1;
1786 break;
1787 case 22:
1788 vc->state.intensity = VCI_NORMAL;
1789 break;
1790 case 23:
1791 vc->state.italic = false;
1792 break;
1793 case 24:
1794 vc->state.underline = false;
1795 break;
1796 case 25:
1797 vc->state.blink = false;
1798 break;
1799 case 27:
1800 vc->state.reverse = false;
1801 break;
1802 case 38:
1803 i = vc_t416_color(vc, i, rgb_foreground);
1804 break;
1805 case 48:
1806 i = vc_t416_color(vc, i, rgb_background);
1807 break;
1808 case 39:
1809 vc->state.color = (vc->vc_def_color & 0x0f) |
1810 (vc->state.color & 0xf0);
1811 break;
1812 case 49:
1813 vc->state.color = (vc->vc_def_color & 0xf0) |
1814 (vc->state.color & 0x0f);
1815 break;
1816 default:
1817 if (vc->vc_par[i] >= 90 && vc->vc_par[i] <= 107) {
1818 if (vc->vc_par[i] < 100)
1819 vc->state.intensity = VCI_BOLD;
1820 vc->vc_par[i] -= 60;
1821 }
1822 if (vc->vc_par[i] >= 30 && vc->vc_par[i] <= 37)
1823 vc->state.color = color_table[vc->vc_par[i] - 30]
1824 | (vc->state.color & 0xf0);
1825 else if (vc->vc_par[i] >= 40 && vc->vc_par[i] <= 47)
1826 vc->state.color = (color_table[vc->vc_par[i] - 40] << 4)
1827 | (vc->state.color & 0x0f);
1828 break;
1829 }
1830 update_attr(vc);
1831 }
1832
1833 static void respond_string(const char *p, size_t len, struct tty_port *port)
1834 {
1835 tty_insert_flip_string(port, p, len);
1836 tty_flip_buffer_push(port);
1837 }
1838
1839 static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
1840 {
1841 char buf[40];
1842 int len;
1843
1844 len = sprintf(buf, "\033[%d;%dR", vc->state.y +
1845 (vc->vc_decom ? vc->vc_top + 1 : 1),
1846 vc->state.x + 1);
1847 respond_string(buf, len, tty->port);
1848 }
1849
1850 static inline void status_report(struct tty_struct *tty)
1851 {
1852 static const char teminal_ok[] = "\033[0n";
1853
1854 respond_string(teminal_ok, strlen(teminal_ok), tty->port);
1855 }
1856
1857 static inline void respond_ID(struct tty_struct *tty)
1858 {
1859
1860 static const char vt102_id[] = "\033[?6c";
1861
1862 respond_string(vt102_id, strlen(vt102_id), tty->port);
1863 }
1864
1865 void mouse_report(struct tty_struct *tty, int butt, int mrx, int mry)
1866 {
1867 char buf[8];
1868 int len;
1869
1870 len = sprintf(buf, "\033[M%c%c%c", (char)(' ' + butt),
1871 (char)('!' + mrx), (char)('!' + mry));
1872 respond_string(buf, len, tty->port);
1873 }
1874
1875
1876 int mouse_reporting(void)
1877 {
1878 return vc_cons[fg_console].d->vc_report_mouse;
1879 }
1880
1881
1882 static void set_mode(struct vc_data *vc, int on_off)
1883 {
1884 int i;
1885
1886 for (i = 0; i <= vc->vc_npar; i++)
1887 if (vc->vc_priv == EPdec) {
1888 switch(vc->vc_par[i]) {
1889 case 1:
1890 if (on_off)
1891 set_kbd(vc, decckm);
1892 else
1893 clr_kbd(vc, decckm);
1894 break;
1895 case 3:
1896 #if 0
1897 vc_resize(deccolm ? 132 : 80, vc->vc_rows);
1898
1899
1900 #endif
1901 break;
1902 case 5:
1903 if (vc->vc_decscnm != on_off) {
1904 vc->vc_decscnm = on_off;
1905 invert_screen(vc, 0,
1906 vc->vc_screenbuf_size,
1907 false);
1908 update_attr(vc);
1909 }
1910 break;
1911 case 6:
1912 vc->vc_decom = on_off;
1913 gotoxay(vc, 0, 0);
1914 break;
1915 case 7:
1916 vc->vc_decawm = on_off;
1917 break;
1918 case 8:
1919 if (on_off)
1920 set_kbd(vc, decarm);
1921 else
1922 clr_kbd(vc, decarm);
1923 break;
1924 case 9:
1925 vc->vc_report_mouse = on_off ? 1 : 0;
1926 break;
1927 case 25:
1928 vc->vc_deccm = on_off;
1929 break;
1930 case 1000:
1931 vc->vc_report_mouse = on_off ? 2 : 0;
1932 break;
1933 }
1934 } else {
1935 switch(vc->vc_par[i]) {
1936 case 3:
1937 vc->vc_disp_ctrl = on_off;
1938 break;
1939 case 4:
1940 vc->vc_decim = on_off;
1941 break;
1942 case 20:
1943 if (on_off)
1944 set_kbd(vc, lnm);
1945 else
1946 clr_kbd(vc, lnm);
1947 break;
1948 }
1949 }
1950 }
1951
1952
1953 static void setterm_command(struct vc_data *vc)
1954 {
1955 switch (vc->vc_par[0]) {
1956 case 1:
1957 if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
1958 vc->vc_ulcolor = color_table[vc->vc_par[1]];
1959 if (vc->state.underline)
1960 update_attr(vc);
1961 }
1962 break;
1963 case 2:
1964 if (vc->vc_can_do_color && vc->vc_par[1] < 16) {
1965 vc->vc_halfcolor = color_table[vc->vc_par[1]];
1966 if (vc->state.intensity == VCI_HALF_BRIGHT)
1967 update_attr(vc);
1968 }
1969 break;
1970 case 8:
1971 vc->vc_def_color = vc->vc_attr;
1972 if (vc->vc_hi_font_mask == 0x100)
1973 vc->vc_def_color >>= 1;
1974 default_attr(vc);
1975 update_attr(vc);
1976 break;
1977 case 9:
1978 blankinterval = min(vc->vc_par[1], 60U) * 60;
1979 poke_blanked_console();
1980 break;
1981 case 10:
1982 if (vc->vc_npar >= 1)
1983 vc->vc_bell_pitch = vc->vc_par[1];
1984 else
1985 vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
1986 break;
1987 case 11:
1988 if (vc->vc_npar >= 1)
1989 vc->vc_bell_duration = (vc->vc_par[1] < 2000) ?
1990 msecs_to_jiffies(vc->vc_par[1]) : 0;
1991 else
1992 vc->vc_bell_duration = DEFAULT_BELL_DURATION;
1993 break;
1994 case 12:
1995 if (vc->vc_par[1] >= 1 && vc_cons_allocated(vc->vc_par[1] - 1))
1996 set_console(vc->vc_par[1] - 1);
1997 break;
1998 case 13:
1999 poke_blanked_console();
2000 break;
2001 case 14:
2002 vesa_off_interval = min(vc->vc_par[1], 60U) * 60 * HZ;
2003 break;
2004 case 15:
2005 set_console(last_console);
2006 break;
2007 case 16:
2008 if (vc->vc_npar >= 1 && vc->vc_par[1] >= 50 &&
2009 vc->vc_par[1] <= USHRT_MAX)
2010 vc->vc_cur_blink_ms = vc->vc_par[1];
2011 else
2012 vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
2013 break;
2014 }
2015 }
2016
2017
2018 static void csi_at(struct vc_data *vc, unsigned int nr)
2019 {
2020 if (nr > vc->vc_cols - vc->state.x)
2021 nr = vc->vc_cols - vc->state.x;
2022 else if (!nr)
2023 nr = 1;
2024 insert_char(vc, nr);
2025 }
2026
2027
2028 static void csi_L(struct vc_data *vc, unsigned int nr)
2029 {
2030 if (nr > vc->vc_rows - vc->state.y)
2031 nr = vc->vc_rows - vc->state.y;
2032 else if (!nr)
2033 nr = 1;
2034 con_scroll(vc, vc->state.y, vc->vc_bottom, SM_DOWN, nr);
2035 vc->vc_need_wrap = 0;
2036 }
2037
2038
2039 static void csi_P(struct vc_data *vc, unsigned int nr)
2040 {
2041 if (nr > vc->vc_cols - vc->state.x)
2042 nr = vc->vc_cols - vc->state.x;
2043 else if (!nr)
2044 nr = 1;
2045 delete_char(vc, nr);
2046 }
2047
2048
2049 static void csi_M(struct vc_data *vc, unsigned int nr)
2050 {
2051 if (nr > vc->vc_rows - vc->state.y)
2052 nr = vc->vc_rows - vc->state.y;
2053 else if (!nr)
2054 nr=1;
2055 con_scroll(vc, vc->state.y, vc->vc_bottom, SM_UP, nr);
2056 vc->vc_need_wrap = 0;
2057 }
2058
2059
2060 static void save_cur(struct vc_data *vc)
2061 {
2062 memcpy(&vc->saved_state, &vc->state, sizeof(vc->state));
2063 }
2064
2065
2066 static void restore_cur(struct vc_data *vc)
2067 {
2068 memcpy(&vc->state, &vc->saved_state, sizeof(vc->state));
2069
2070 gotoxy(vc, vc->state.x, vc->state.y);
2071 vc->vc_translate = set_translate(vc->state.Gx_charset[vc->state.charset],
2072 vc);
2073 update_attr(vc);
2074 vc->vc_need_wrap = 0;
2075 }
2076
2077 enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey,
2078 EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd,
2079 ESpalette, ESosc, ESapc, ESpm, ESdcs };
2080
2081
2082 static void reset_terminal(struct vc_data *vc, int do_clear)
2083 {
2084 unsigned int i;
2085
2086 vc->vc_top = 0;
2087 vc->vc_bottom = vc->vc_rows;
2088 vc->vc_state = ESnormal;
2089 vc->vc_priv = EPecma;
2090 vc->vc_translate = set_translate(LAT1_MAP, vc);
2091 vc->state.Gx_charset[0] = LAT1_MAP;
2092 vc->state.Gx_charset[1] = GRAF_MAP;
2093 vc->state.charset = 0;
2094 vc->vc_need_wrap = 0;
2095 vc->vc_report_mouse = 0;
2096 vc->vc_utf = default_utf8;
2097 vc->vc_utf_count = 0;
2098
2099 vc->vc_disp_ctrl = 0;
2100 vc->vc_toggle_meta = 0;
2101
2102 vc->vc_decscnm = 0;
2103 vc->vc_decom = 0;
2104 vc->vc_decawm = 1;
2105 vc->vc_deccm = global_cursor_default;
2106 vc->vc_decim = 0;
2107
2108 vt_reset_keyboard(vc->vc_num);
2109
2110 vc->vc_cursor_type = cur_default;
2111 vc->vc_complement_mask = vc->vc_s_complement_mask;
2112
2113 default_attr(vc);
2114 update_attr(vc);
2115
2116 bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
2117 for (i = 0; i < VC_TABSTOPS_COUNT; i += 8)
2118 set_bit(i, vc->vc_tab_stop);
2119
2120 vc->vc_bell_pitch = DEFAULT_BELL_PITCH;
2121 vc->vc_bell_duration = DEFAULT_BELL_DURATION;
2122 vc->vc_cur_blink_ms = DEFAULT_CURSOR_BLINK_MS;
2123
2124 gotoxy(vc, 0, 0);
2125 save_cur(vc);
2126 if (do_clear)
2127 csi_J(vc, 2);
2128 }
2129
2130 static void vc_setGx(struct vc_data *vc, unsigned int which, int c)
2131 {
2132 unsigned char *charset = &vc->state.Gx_charset[which];
2133
2134 switch (c) {
2135 case '0':
2136 *charset = GRAF_MAP;
2137 break;
2138 case 'B':
2139 *charset = LAT1_MAP;
2140 break;
2141 case 'U':
2142 *charset = IBMPC_MAP;
2143 break;
2144 case 'K':
2145 *charset = USER_MAP;
2146 break;
2147 }
2148
2149 if (vc->state.charset == which)
2150 vc->vc_translate = set_translate(*charset, vc);
2151 }
2152
2153
2154 static bool ansi_control_string(unsigned int state)
2155 {
2156 if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs)
2157 return true;
2158 return false;
2159 }
2160
2161
2162 static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
2163 {
2164
2165
2166
2167
2168 if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13)
2169 return;
2170 switch (c) {
2171 case 0:
2172 return;
2173 case 7:
2174 if (ansi_control_string(vc->vc_state))
2175 vc->vc_state = ESnormal;
2176 else if (vc->vc_bell_duration)
2177 kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration);
2178 return;
2179 case 8:
2180 bs(vc);
2181 return;
2182 case 9:
2183 vc->vc_pos -= (vc->state.x << 1);
2184
2185 vc->state.x = find_next_bit(vc->vc_tab_stop,
2186 min(vc->vc_cols - 1, VC_TABSTOPS_COUNT),
2187 vc->state.x + 1);
2188 if (vc->state.x >= VC_TABSTOPS_COUNT)
2189 vc->state.x = vc->vc_cols - 1;
2190
2191 vc->vc_pos += (vc->state.x << 1);
2192 notify_write(vc, '\t');
2193 return;
2194 case 10: case 11: case 12:
2195 lf(vc);
2196 if (!is_kbd(vc, lnm))
2197 return;
2198 fallthrough;
2199 case 13:
2200 cr(vc);
2201 return;
2202 case 14:
2203 vc->state.charset = 1;
2204 vc->vc_translate = set_translate(vc->state.Gx_charset[1], vc);
2205 vc->vc_disp_ctrl = 1;
2206 return;
2207 case 15:
2208 vc->state.charset = 0;
2209 vc->vc_translate = set_translate(vc->state.Gx_charset[0], vc);
2210 vc->vc_disp_ctrl = 0;
2211 return;
2212 case 24: case 26:
2213 vc->vc_state = ESnormal;
2214 return;
2215 case 27:
2216 vc->vc_state = ESesc;
2217 return;
2218 case 127:
2219 del(vc);
2220 return;
2221 case 128+27:
2222 vc->vc_state = ESsquare;
2223 return;
2224 }
2225 switch(vc->vc_state) {
2226 case ESesc:
2227 vc->vc_state = ESnormal;
2228 switch (c) {
2229 case '[':
2230 vc->vc_state = ESsquare;
2231 return;
2232 case ']':
2233 vc->vc_state = ESnonstd;
2234 return;
2235 case '_':
2236 vc->vc_state = ESapc;
2237 return;
2238 case '^':
2239 vc->vc_state = ESpm;
2240 return;
2241 case '%':
2242 vc->vc_state = ESpercent;
2243 return;
2244 case 'E':
2245 cr(vc);
2246 lf(vc);
2247 return;
2248 case 'M':
2249 ri(vc);
2250 return;
2251 case 'D':
2252 lf(vc);
2253 return;
2254 case 'H':
2255 if (vc->state.x < VC_TABSTOPS_COUNT)
2256 set_bit(vc->state.x, vc->vc_tab_stop);
2257 return;
2258 case 'P':
2259 vc->vc_state = ESdcs;
2260 return;
2261 case 'Z':
2262 respond_ID(tty);
2263 return;
2264 case '7':
2265 save_cur(vc);
2266 return;
2267 case '8':
2268 restore_cur(vc);
2269 return;
2270 case '(':
2271 vc->vc_state = ESsetG0;
2272 return;
2273 case ')':
2274 vc->vc_state = ESsetG1;
2275 return;
2276 case '#':
2277 vc->vc_state = EShash;
2278 return;
2279 case 'c':
2280 reset_terminal(vc, 1);
2281 return;
2282 case '>':
2283 clr_kbd(vc, kbdapplic);
2284 return;
2285 case '=':
2286 set_kbd(vc, kbdapplic);
2287 return;
2288 }
2289 return;
2290 case ESnonstd:
2291 if (c=='P') {
2292 for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
2293 vc->vc_par[vc->vc_npar] = 0;
2294 vc->vc_npar = 0;
2295 vc->vc_state = ESpalette;
2296 return;
2297 } else if (c=='R') {
2298 reset_palette(vc);
2299 vc->vc_state = ESnormal;
2300 } else if (c>='0' && c<='9')
2301 vc->vc_state = ESosc;
2302 else
2303 vc->vc_state = ESnormal;
2304 return;
2305 case ESpalette:
2306 if (isxdigit(c)) {
2307 vc->vc_par[vc->vc_npar++] = hex_to_bin(c);
2308 if (vc->vc_npar == 7) {
2309 int i = vc->vc_par[0] * 3, j = 1;
2310 vc->vc_palette[i] = 16 * vc->vc_par[j++];
2311 vc->vc_palette[i++] += vc->vc_par[j++];
2312 vc->vc_palette[i] = 16 * vc->vc_par[j++];
2313 vc->vc_palette[i++] += vc->vc_par[j++];
2314 vc->vc_palette[i] = 16 * vc->vc_par[j++];
2315 vc->vc_palette[i] += vc->vc_par[j];
2316 set_palette(vc);
2317 vc->vc_state = ESnormal;
2318 }
2319 } else
2320 vc->vc_state = ESnormal;
2321 return;
2322 case ESsquare:
2323 for (vc->vc_npar = 0; vc->vc_npar < NPAR; vc->vc_npar++)
2324 vc->vc_par[vc->vc_npar] = 0;
2325 vc->vc_npar = 0;
2326 vc->vc_state = ESgetpars;
2327 if (c == '[') {
2328 vc->vc_state=ESfunckey;
2329 return;
2330 }
2331 switch (c) {
2332 case '?':
2333 vc->vc_priv = EPdec;
2334 return;
2335 case '>':
2336 vc->vc_priv = EPgt;
2337 return;
2338 case '=':
2339 vc->vc_priv = EPeq;
2340 return;
2341 case '<':
2342 vc->vc_priv = EPlt;
2343 return;
2344 }
2345 vc->vc_priv = EPecma;
2346 fallthrough;
2347 case ESgetpars:
2348 if (c == ';' && vc->vc_npar < NPAR - 1) {
2349 vc->vc_npar++;
2350 return;
2351 } else if (c>='0' && c<='9') {
2352 vc->vc_par[vc->vc_npar] *= 10;
2353 vc->vc_par[vc->vc_npar] += c - '0';
2354 return;
2355 }
2356 if (c >= 0x20 && c <= 0x3f) {
2357 vc->vc_state = EScsiignore;
2358 return;
2359 }
2360 vc->vc_state = ESnormal;
2361 switch(c) {
2362 case 'h':
2363 if (vc->vc_priv <= EPdec)
2364 set_mode(vc, 1);
2365 return;
2366 case 'l':
2367 if (vc->vc_priv <= EPdec)
2368 set_mode(vc, 0);
2369 return;
2370 case 'c':
2371 if (vc->vc_priv == EPdec) {
2372 if (vc->vc_par[0])
2373 vc->vc_cursor_type =
2374 CUR_MAKE(vc->vc_par[0],
2375 vc->vc_par[1],
2376 vc->vc_par[2]);
2377 else
2378 vc->vc_cursor_type = cur_default;
2379 return;
2380 }
2381 break;
2382 case 'm':
2383 if (vc->vc_priv == EPdec) {
2384 clear_selection();
2385 if (vc->vc_par[0])
2386 vc->vc_complement_mask = vc->vc_par[0] << 8 | vc->vc_par[1];
2387 else
2388 vc->vc_complement_mask = vc->vc_s_complement_mask;
2389 return;
2390 }
2391 break;
2392 case 'n':
2393 if (vc->vc_priv == EPecma) {
2394 if (vc->vc_par[0] == 5)
2395 status_report(tty);
2396 else if (vc->vc_par[0] == 6)
2397 cursor_report(vc, tty);
2398 }
2399 return;
2400 }
2401 if (vc->vc_priv != EPecma) {
2402 vc->vc_priv = EPecma;
2403 return;
2404 }
2405 switch(c) {
2406 case 'G': case '`':
2407 if (vc->vc_par[0])
2408 vc->vc_par[0]--;
2409 gotoxy(vc, vc->vc_par[0], vc->state.y);
2410 return;
2411 case 'A':
2412 if (!vc->vc_par[0])
2413 vc->vc_par[0]++;
2414 gotoxy(vc, vc->state.x, vc->state.y - vc->vc_par[0]);
2415 return;
2416 case 'B': case 'e':
2417 if (!vc->vc_par[0])
2418 vc->vc_par[0]++;
2419 gotoxy(vc, vc->state.x, vc->state.y + vc->vc_par[0]);
2420 return;
2421 case 'C': case 'a':
2422 if (!vc->vc_par[0])
2423 vc->vc_par[0]++;
2424 gotoxy(vc, vc->state.x + vc->vc_par[0], vc->state.y);
2425 return;
2426 case 'D':
2427 if (!vc->vc_par[0])
2428 vc->vc_par[0]++;
2429 gotoxy(vc, vc->state.x - vc->vc_par[0], vc->state.y);
2430 return;
2431 case 'E':
2432 if (!vc->vc_par[0])
2433 vc->vc_par[0]++;
2434 gotoxy(vc, 0, vc->state.y + vc->vc_par[0]);
2435 return;
2436 case 'F':
2437 if (!vc->vc_par[0])
2438 vc->vc_par[0]++;
2439 gotoxy(vc, 0, vc->state.y - vc->vc_par[0]);
2440 return;
2441 case 'd':
2442 if (vc->vc_par[0])
2443 vc->vc_par[0]--;
2444 gotoxay(vc, vc->state.x ,vc->vc_par[0]);
2445 return;
2446 case 'H': case 'f':
2447 if (vc->vc_par[0])
2448 vc->vc_par[0]--;
2449 if (vc->vc_par[1])
2450 vc->vc_par[1]--;
2451 gotoxay(vc, vc->vc_par[1], vc->vc_par[0]);
2452 return;
2453 case 'J':
2454 csi_J(vc, vc->vc_par[0]);
2455 return;
2456 case 'K':
2457 csi_K(vc, vc->vc_par[0]);
2458 return;
2459 case 'L':
2460 csi_L(vc, vc->vc_par[0]);
2461 return;
2462 case 'M':
2463 csi_M(vc, vc->vc_par[0]);
2464 return;
2465 case 'P':
2466 csi_P(vc, vc->vc_par[0]);
2467 return;
2468 case 'c':
2469 if (!vc->vc_par[0])
2470 respond_ID(tty);
2471 return;
2472 case 'g':
2473 if (!vc->vc_par[0] && vc->state.x < VC_TABSTOPS_COUNT)
2474 set_bit(vc->state.x, vc->vc_tab_stop);
2475 else if (vc->vc_par[0] == 3)
2476 bitmap_zero(vc->vc_tab_stop, VC_TABSTOPS_COUNT);
2477 return;
2478 case 'm':
2479 csi_m(vc);
2480 return;
2481 case 'q':
2482
2483 if (vc->vc_par[0] < 4)
2484 vt_set_led_state(vc->vc_num,
2485 (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4);
2486 return;
2487 case 'r':
2488 if (!vc->vc_par[0])
2489 vc->vc_par[0]++;
2490 if (!vc->vc_par[1])
2491 vc->vc_par[1] = vc->vc_rows;
2492
2493 if (vc->vc_par[0] < vc->vc_par[1] &&
2494 vc->vc_par[1] <= vc->vc_rows) {
2495 vc->vc_top = vc->vc_par[0] - 1;
2496 vc->vc_bottom = vc->vc_par[1];
2497 gotoxay(vc, 0, 0);
2498 }
2499 return;
2500 case 's':
2501 save_cur(vc);
2502 return;
2503 case 'u':
2504 restore_cur(vc);
2505 return;
2506 case 'X':
2507 csi_X(vc, vc->vc_par[0]);
2508 return;
2509 case '@':
2510 csi_at(vc, vc->vc_par[0]);
2511 return;
2512 case ']':
2513 setterm_command(vc);
2514 return;
2515 }
2516 return;
2517 case EScsiignore:
2518 if (c >= 20 && c <= 0x3f)
2519 return;
2520 vc->vc_state = ESnormal;
2521 return;
2522 case ESpercent:
2523 vc->vc_state = ESnormal;
2524 switch (c) {
2525 case '@':
2526 vc->vc_utf = 0;
2527 return;
2528 case 'G':
2529 case '8':
2530 vc->vc_utf = 1;
2531 return;
2532 }
2533 return;
2534 case ESfunckey:
2535 vc->vc_state = ESnormal;
2536 return;
2537 case EShash:
2538 vc->vc_state = ESnormal;
2539 if (c == '8') {
2540
2541 vc->vc_video_erase_char =
2542 (vc->vc_video_erase_char & 0xff00) | 'E';
2543 csi_J(vc, 2);
2544 vc->vc_video_erase_char =
2545 (vc->vc_video_erase_char & 0xff00) | ' ';
2546 do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2);
2547 }
2548 return;
2549 case ESsetG0:
2550 vc_setGx(vc, 0, c);
2551 vc->vc_state = ESnormal;
2552 return;
2553 case ESsetG1:
2554 vc_setGx(vc, 1, c);
2555 vc->vc_state = ESnormal;
2556 return;
2557 case ESapc:
2558 return;
2559 case ESosc:
2560 return;
2561 case ESpm:
2562 return;
2563 case ESdcs:
2564 return;
2565 default:
2566 vc->vc_state = ESnormal;
2567 }
2568 }
2569
2570
2571
2572
2573
2574 struct interval {
2575 uint32_t first;
2576 uint32_t last;
2577 };
2578
2579 static int ucs_cmp(const void *key, const void *elt)
2580 {
2581 uint32_t ucs = *(uint32_t *)key;
2582 struct interval e = *(struct interval *) elt;
2583
2584 if (ucs > e.last)
2585 return 1;
2586 else if (ucs < e.first)
2587 return -1;
2588 return 0;
2589 }
2590
2591 static int is_double_width(uint32_t ucs)
2592 {
2593 static const struct interval double_width[] = {
2594 { 0x1100, 0x115F }, { 0x2329, 0x232A }, { 0x2E80, 0x303E },
2595 { 0x3040, 0xA4CF }, { 0xAC00, 0xD7A3 }, { 0xF900, 0xFAFF },
2596 { 0xFE10, 0xFE19 }, { 0xFE30, 0xFE6F }, { 0xFF00, 0xFF60 },
2597 { 0xFFE0, 0xFFE6 }, { 0x20000, 0x2FFFD }, { 0x30000, 0x3FFFD }
2598 };
2599 if (ucs < double_width[0].first ||
2600 ucs > double_width[ARRAY_SIZE(double_width) - 1].last)
2601 return 0;
2602
2603 return bsearch(&ucs, double_width, ARRAY_SIZE(double_width),
2604 sizeof(struct interval), ucs_cmp) != NULL;
2605 }
2606
2607 struct vc_draw_region {
2608 unsigned long from, to;
2609 int x;
2610 };
2611
2612 static void con_flush(struct vc_data *vc, struct vc_draw_region *draw)
2613 {
2614 if (draw->x < 0)
2615 return;
2616
2617 vc->vc_sw->con_putcs(vc, (u16 *)draw->from,
2618 (u16 *)draw->to - (u16 *)draw->from, vc->state.y,
2619 draw->x);
2620 draw->x = -1;
2621 }
2622
2623 static inline int vc_translate_ascii(const struct vc_data *vc, int c)
2624 {
2625 if (IS_ENABLED(CONFIG_CONSOLE_TRANSLATIONS)) {
2626 if (vc->vc_toggle_meta)
2627 c |= 0x80;
2628
2629 return vc->vc_translate[c];
2630 }
2631
2632 return c;
2633 }
2634
2635
2636
2637
2638
2639
2640 static inline int vc_sanitize_unicode(const int c)
2641 {
2642 if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
2643 return 0xfffd;
2644
2645 return c;
2646 }
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658 static int vc_translate_unicode(struct vc_data *vc, int c, bool *rescan)
2659 {
2660 static const u32 utf8_length_changes[] = {
2661 0x0000007f, 0x000007ff, 0x0000ffff,
2662 0x001fffff, 0x03ffffff, 0x7fffffff
2663 };
2664
2665
2666 if ((c & 0xc0) == 0x80) {
2667
2668 if (!vc->vc_utf_count)
2669 return 0xfffd;
2670
2671 vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
2672 vc->vc_npar++;
2673 if (--vc->vc_utf_count)
2674 goto need_more_bytes;
2675
2676
2677 c = vc->vc_utf_char;
2678
2679 if (c <= utf8_length_changes[vc->vc_npar - 1] ||
2680 c > utf8_length_changes[vc->vc_npar])
2681 return 0xfffd;
2682
2683 return vc_sanitize_unicode(c);
2684 }
2685
2686
2687 if (vc->vc_utf_count) {
2688
2689 *rescan = true;
2690 vc->vc_utf_count = 0;
2691 return 0xfffd;
2692 }
2693
2694
2695 if (c <= 0x7f)
2696 return c;
2697
2698
2699 vc->vc_npar = 0;
2700 if ((c & 0xe0) == 0xc0) {
2701 vc->vc_utf_count = 1;
2702 vc->vc_utf_char = (c & 0x1f);
2703 } else if ((c & 0xf0) == 0xe0) {
2704 vc->vc_utf_count = 2;
2705 vc->vc_utf_char = (c & 0x0f);
2706 } else if ((c & 0xf8) == 0xf0) {
2707 vc->vc_utf_count = 3;
2708 vc->vc_utf_char = (c & 0x07);
2709 } else if ((c & 0xfc) == 0xf8) {
2710 vc->vc_utf_count = 4;
2711 vc->vc_utf_char = (c & 0x03);
2712 } else if ((c & 0xfe) == 0xfc) {
2713 vc->vc_utf_count = 5;
2714 vc->vc_utf_char = (c & 0x01);
2715 } else {
2716
2717 return 0xfffd;
2718 }
2719
2720 need_more_bytes:
2721 return -1;
2722 }
2723
2724 static int vc_translate(struct vc_data *vc, int *c, bool *rescan)
2725 {
2726
2727 if (vc->vc_state != ESnormal)
2728 return *c;
2729
2730 if (vc->vc_utf && !vc->vc_disp_ctrl)
2731 return *c = vc_translate_unicode(vc, *c, rescan);
2732
2733
2734 return vc_translate_ascii(vc, *c);
2735 }
2736
2737 static inline unsigned char vc_invert_attr(const struct vc_data *vc)
2738 {
2739 if (!vc->vc_can_do_color)
2740 return vc->vc_attr ^ 0x08;
2741
2742 if (vc->vc_hi_font_mask == 0x100)
2743 return (vc->vc_attr & 0x11) |
2744 ((vc->vc_attr & 0xe0) >> 4) |
2745 ((vc->vc_attr & 0x0e) << 4);
2746
2747 return (vc->vc_attr & 0x88) |
2748 ((vc->vc_attr & 0x70) >> 4) |
2749 ((vc->vc_attr & 0x07) << 4);
2750 }
2751
2752 static bool vc_is_control(struct vc_data *vc, int tc, int c)
2753 {
2754
2755
2756
2757
2758
2759
2760 static const u32 CTRL_ACTION = 0x0d00ff81;
2761
2762 static const u32 CTRL_ALWAYS = 0x0800f501;
2763
2764 if (vc->vc_state != ESnormal)
2765 return true;
2766
2767 if (!tc)
2768 return true;
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779 if (c < 32) {
2780 if (vc->vc_disp_ctrl)
2781 return CTRL_ALWAYS & BIT(c);
2782 else
2783 return vc->vc_utf || (CTRL_ACTION & BIT(c));
2784 }
2785
2786 if (c == 127 && !vc->vc_disp_ctrl)
2787 return true;
2788
2789 if (c == 128 + 27)
2790 return true;
2791
2792 return false;
2793 }
2794
2795 static int vc_con_write_normal(struct vc_data *vc, int tc, int c,
2796 struct vc_draw_region *draw)
2797 {
2798 int next_c;
2799 unsigned char vc_attr = vc->vc_attr;
2800 u16 himask = vc->vc_hi_font_mask, charmask = himask ? 0x1ff : 0xff;
2801 u8 width = 1;
2802 bool inverse = false;
2803
2804 if (vc->vc_utf && !vc->vc_disp_ctrl) {
2805 if (is_double_width(c))
2806 width = 2;
2807 }
2808
2809
2810 tc = conv_uni_to_pc(vc, tc);
2811 if (tc & ~charmask) {
2812 if (tc == -1 || tc == -2)
2813 return -1;
2814
2815
2816 if ((!vc->vc_utf || vc->vc_disp_ctrl || c < 128) &&
2817 !(c & ~charmask)) {
2818
2819
2820
2821
2822
2823
2824
2825
2826 tc = c;
2827 } else {
2828
2829
2830
2831
2832 tc = conv_uni_to_pc(vc, 0xfffd);
2833 if (tc < 0) {
2834 inverse = true;
2835 tc = conv_uni_to_pc(vc, '?');
2836 if (tc < 0)
2837 tc = '?';
2838
2839 vc_attr = vc_invert_attr(vc);
2840 con_flush(vc, draw);
2841 }
2842 }
2843 }
2844
2845 next_c = c;
2846 while (1) {
2847 if (vc->vc_need_wrap || vc->vc_decim)
2848 con_flush(vc, draw);
2849 if (vc->vc_need_wrap) {
2850 cr(vc);
2851 lf(vc);
2852 }
2853 if (vc->vc_decim)
2854 insert_char(vc, 1);
2855 vc_uniscr_putc(vc, next_c);
2856
2857 if (himask)
2858 tc = ((tc & 0x100) ? himask : 0) |
2859 (tc & 0xff);
2860 tc |= (vc_attr << 8) & ~himask;
2861
2862 scr_writew(tc, (u16 *)vc->vc_pos);
2863
2864 if (con_should_update(vc) && draw->x < 0) {
2865 draw->x = vc->state.x;
2866 draw->from = vc->vc_pos;
2867 }
2868 if (vc->state.x == vc->vc_cols - 1) {
2869 vc->vc_need_wrap = vc->vc_decawm;
2870 draw->to = vc->vc_pos + 2;
2871 } else {
2872 vc->state.x++;
2873 draw->to = (vc->vc_pos += 2);
2874 }
2875
2876 if (!--width)
2877 break;
2878
2879
2880 tc = conv_uni_to_pc(vc, ' ');
2881 if (tc < 0)
2882 tc = ' ';
2883 next_c = ' ';
2884 }
2885 notify_write(vc, c);
2886
2887 if (inverse)
2888 con_flush(vc, draw);
2889
2890 return 0;
2891 }
2892
2893
2894 static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
2895 {
2896 struct vc_draw_region draw = {
2897 .x = -1,
2898 };
2899 int c, tc, n = 0;
2900 unsigned int currcons;
2901 struct vc_data *vc;
2902 struct vt_notifier_param param;
2903 bool rescan;
2904
2905 if (in_interrupt())
2906 return count;
2907
2908 console_lock();
2909 vc = tty->driver_data;
2910 if (vc == NULL) {
2911 pr_err("vt: argh, driver_data is NULL !\n");
2912 console_unlock();
2913 return 0;
2914 }
2915
2916 currcons = vc->vc_num;
2917 if (!vc_cons_allocated(currcons)) {
2918
2919 pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
2920 console_unlock();
2921 return 0;
2922 }
2923
2924
2925
2926 if (con_is_fg(vc))
2927 hide_cursor(vc);
2928
2929 param.vc = vc;
2930
2931 while (!tty->flow.stopped && count) {
2932 int orig = *buf;
2933 buf++;
2934 n++;
2935 count--;
2936 rescan_last_byte:
2937 c = orig;
2938 rescan = false;
2939
2940 tc = vc_translate(vc, &c, &rescan);
2941 if (tc == -1)
2942 continue;
2943
2944 param.c = tc;
2945 if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
2946 ¶m) == NOTIFY_STOP)
2947 continue;
2948
2949 if (vc_is_control(vc, tc, c)) {
2950 con_flush(vc, &draw);
2951 do_con_trol(tty, vc, orig);
2952 continue;
2953 }
2954
2955 if (vc_con_write_normal(vc, tc, c, &draw) < 0)
2956 continue;
2957
2958 if (rescan)
2959 goto rescan_last_byte;
2960 }
2961 con_flush(vc, &draw);
2962 vc_uniscr_debug_check(vc);
2963 console_conditional_schedule();
2964 notify_update(vc);
2965 console_unlock();
2966 return n;
2967 }
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978 static void console_callback(struct work_struct *ignored)
2979 {
2980 console_lock();
2981
2982 if (want_console >= 0) {
2983 if (want_console != fg_console &&
2984 vc_cons_allocated(want_console)) {
2985 hide_cursor(vc_cons[fg_console].d);
2986 change_console(vc_cons[want_console].d);
2987
2988
2989
2990 }
2991 want_console = -1;
2992 }
2993 if (do_poke_blanked_console) {
2994 do_poke_blanked_console = 0;
2995 poke_blanked_console();
2996 }
2997 if (scrollback_delta) {
2998 struct vc_data *vc = vc_cons[fg_console].d;
2999 clear_selection();
3000 if (vc->vc_mode == KD_TEXT && vc->vc_sw->con_scrolldelta)
3001 vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
3002 scrollback_delta = 0;
3003 }
3004 if (blank_timer_expired) {
3005 do_blank_screen(0);
3006 blank_timer_expired = 0;
3007 }
3008 notify_update(vc_cons[fg_console].d);
3009
3010 console_unlock();
3011 }
3012
3013 int set_console(int nr)
3014 {
3015 struct vc_data *vc = vc_cons[fg_console].d;
3016
3017 if (!vc_cons_allocated(nr) || vt_dont_switch ||
3018 (vc->vt_mode.mode == VT_AUTO && vc->vc_mode == KD_GRAPHICS)) {
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028 return -EINVAL;
3029 }
3030
3031 want_console = nr;
3032 schedule_console_callback();
3033
3034 return 0;
3035 }
3036
3037 struct tty_driver *console_driver;
3038
3039 #ifdef CONFIG_VT_CONSOLE
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062 int vt_kmsg_redirect(int new)
3063 {
3064 static int kmsg_con;
3065
3066 if (new != -1)
3067 return xchg(&kmsg_con, new);
3068 else
3069 return kmsg_con;
3070 }
3071
3072
3073
3074
3075
3076
3077
3078 static void vt_console_print(struct console *co, const char *b, unsigned count)
3079 {
3080 struct vc_data *vc = vc_cons[fg_console].d;
3081 unsigned char c;
3082 static DEFINE_SPINLOCK(printing_lock);
3083 const ushort *start;
3084 ushort start_x, cnt;
3085 int kmsg_console;
3086
3087
3088 if (!printable)
3089 return;
3090 if (!spin_trylock(&printing_lock))
3091 return;
3092
3093 kmsg_console = vt_get_kmsg_redirect();
3094 if (kmsg_console && vc_cons_allocated(kmsg_console - 1))
3095 vc = vc_cons[kmsg_console - 1].d;
3096
3097 if (!vc_cons_allocated(fg_console)) {
3098
3099
3100 goto quit;
3101 }
3102
3103 if (vc->vc_mode != KD_TEXT)
3104 goto quit;
3105
3106
3107 if (con_is_fg(vc))
3108 hide_cursor(vc);
3109
3110 start = (ushort *)vc->vc_pos;
3111 start_x = vc->state.x;
3112 cnt = 0;
3113 while (count--) {
3114 c = *b++;
3115 if (c == 10 || c == 13 || c == 8 || vc->vc_need_wrap) {
3116 if (cnt && con_is_visible(vc))
3117 vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
3118 cnt = 0;
3119 if (c == 8) {
3120 bs(vc);
3121 start = (ushort *)vc->vc_pos;
3122 start_x = vc->state.x;
3123 continue;
3124 }
3125 if (c != 13)
3126 lf(vc);
3127 cr(vc);
3128 start = (ushort *)vc->vc_pos;
3129 start_x = vc->state.x;
3130 if (c == 10 || c == 13)
3131 continue;
3132 }
3133 vc_uniscr_putc(vc, c);
3134 scr_writew((vc->vc_attr << 8) + c, (unsigned short *)vc->vc_pos);
3135 notify_write(vc, c);
3136 cnt++;
3137 if (vc->state.x == vc->vc_cols - 1) {
3138 vc->vc_need_wrap = 1;
3139 } else {
3140 vc->vc_pos += 2;
3141 vc->state.x++;
3142 }
3143 }
3144 if (cnt && con_is_visible(vc))
3145 vc->vc_sw->con_putcs(vc, start, cnt, vc->state.y, start_x);
3146 set_cursor(vc);
3147 notify_update(vc);
3148
3149 quit:
3150 spin_unlock(&printing_lock);
3151 }
3152
3153 static struct tty_driver *vt_console_device(struct console *c, int *index)
3154 {
3155 *index = c->index ? c->index-1 : fg_console;
3156 return console_driver;
3157 }
3158
3159 static struct console vt_console_driver = {
3160 .name = "tty",
3161 .write = vt_console_print,
3162 .device = vt_console_device,
3163 .unblank = unblank_screen,
3164 .flags = CON_PRINTBUFFER,
3165 .index = -1,
3166 };
3167 #endif
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184 int tioclinux(struct tty_struct *tty, unsigned long arg)
3185 {
3186 char type, data;
3187 char __user *p = (char __user *)arg;
3188 int lines;
3189 int ret;
3190
3191 if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN))
3192 return -EPERM;
3193 if (get_user(type, p))
3194 return -EFAULT;
3195 ret = 0;
3196
3197 switch (type)
3198 {
3199 case TIOCL_SETSEL:
3200 ret = set_selection_user((struct tiocl_selection
3201 __user *)(p+1), tty);
3202 break;
3203 case TIOCL_PASTESEL:
3204 ret = paste_selection(tty);
3205 break;
3206 case TIOCL_UNBLANKSCREEN:
3207 console_lock();
3208 unblank_screen();
3209 console_unlock();
3210 break;
3211 case TIOCL_SELLOADLUT:
3212 console_lock();
3213 ret = sel_loadlut(p);
3214 console_unlock();
3215 break;
3216 case TIOCL_GETSHIFTSTATE:
3217
3218
3219
3220
3221
3222
3223
3224 data = vt_get_shift_state();
3225 ret = put_user(data, p);
3226 break;
3227 case TIOCL_GETMOUSEREPORTING:
3228 console_lock();
3229 data = mouse_reporting();
3230 console_unlock();
3231 ret = put_user(data, p);
3232 break;
3233 case TIOCL_SETVESABLANK:
3234 console_lock();
3235 ret = set_vesa_blanking(p);
3236 console_unlock();
3237 break;
3238 case TIOCL_GETKMSGREDIRECT:
3239 data = vt_get_kmsg_redirect();
3240 ret = put_user(data, p);
3241 break;
3242 case TIOCL_SETKMSGREDIRECT:
3243 if (!capable(CAP_SYS_ADMIN)) {
3244 ret = -EPERM;
3245 } else {
3246 if (get_user(data, p+1))
3247 ret = -EFAULT;
3248 else
3249 vt_kmsg_redirect(data);
3250 }
3251 break;
3252 case TIOCL_GETFGCONSOLE:
3253
3254
3255
3256 ret = fg_console;
3257 break;
3258 case TIOCL_SCROLLCONSOLE:
3259 if (get_user(lines, (s32 __user *)(p+4))) {
3260 ret = -EFAULT;
3261 } else {
3262
3263
3264
3265 console_lock();
3266 scrollfront(vc_cons[fg_console].d, lines);
3267 console_unlock();
3268 ret = 0;
3269 }
3270 break;
3271 case TIOCL_BLANKSCREEN:
3272 console_lock();
3273 ignore_poke = 1;
3274 do_blank_screen(0);
3275 console_unlock();
3276 break;
3277 case TIOCL_BLANKEDSCREEN:
3278 ret = console_blanked;
3279 break;
3280 default:
3281 ret = -EINVAL;
3282 break;
3283 }
3284 return ret;
3285 }
3286
3287
3288
3289
3290
3291 static int con_write(struct tty_struct *tty, const unsigned char *buf, int count)
3292 {
3293 int retval;
3294
3295 retval = do_con_write(tty, buf, count);
3296 con_flush_chars(tty);
3297
3298 return retval;
3299 }
3300
3301 static int con_put_char(struct tty_struct *tty, unsigned char ch)
3302 {
3303 return do_con_write(tty, &ch, 1);
3304 }
3305
3306 static unsigned int con_write_room(struct tty_struct *tty)
3307 {
3308 if (tty->flow.stopped)
3309 return 0;
3310 return 32768;
3311 }
3312
3313
3314
3315
3316
3317
3318 static void con_throttle(struct tty_struct *tty)
3319 {
3320 }
3321
3322 static void con_unthrottle(struct tty_struct *tty)
3323 {
3324 struct vc_data *vc = tty->driver_data;
3325
3326 wake_up_interruptible(&vc->paste_wait);
3327 }
3328
3329
3330
3331
3332 static void con_stop(struct tty_struct *tty)
3333 {
3334 int console_num;
3335 if (!tty)
3336 return;
3337 console_num = tty->index;
3338 if (!vc_cons_allocated(console_num))
3339 return;
3340 vt_kbd_con_stop(console_num);
3341 }
3342
3343
3344
3345
3346 static void con_start(struct tty_struct *tty)
3347 {
3348 int console_num;
3349 if (!tty)
3350 return;
3351 console_num = tty->index;
3352 if (!vc_cons_allocated(console_num))
3353 return;
3354 vt_kbd_con_start(console_num);
3355 }
3356
3357 static void con_flush_chars(struct tty_struct *tty)
3358 {
3359 struct vc_data *vc;
3360
3361 if (in_interrupt())
3362 return;
3363
3364
3365 console_lock();
3366 vc = tty->driver_data;
3367 if (vc)
3368 set_cursor(vc);
3369 console_unlock();
3370 }
3371
3372
3373
3374
3375 static int con_install(struct tty_driver *driver, struct tty_struct *tty)
3376 {
3377 unsigned int currcons = tty->index;
3378 struct vc_data *vc;
3379 int ret;
3380
3381 console_lock();
3382 ret = vc_allocate(currcons);
3383 if (ret)
3384 goto unlock;
3385
3386 vc = vc_cons[currcons].d;
3387
3388
3389 if (vc->port.tty) {
3390 ret = -ERESTARTSYS;
3391 goto unlock;
3392 }
3393
3394 ret = tty_port_install(&vc->port, driver, tty);
3395 if (ret)
3396 goto unlock;
3397
3398 tty->driver_data = vc;
3399 vc->port.tty = tty;
3400 tty_port_get(&vc->port);
3401
3402 if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
3403 tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
3404 tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
3405 }
3406 if (vc->vc_utf)
3407 tty->termios.c_iflag |= IUTF8;
3408 else
3409 tty->termios.c_iflag &= ~IUTF8;
3410 unlock:
3411 console_unlock();
3412 return ret;
3413 }
3414
3415 static int con_open(struct tty_struct *tty, struct file *filp)
3416 {
3417
3418 return 0;
3419 }
3420
3421
3422 static void con_close(struct tty_struct *tty, struct file *filp)
3423 {
3424
3425 }
3426
3427 static void con_shutdown(struct tty_struct *tty)
3428 {
3429 struct vc_data *vc = tty->driver_data;
3430 BUG_ON(vc == NULL);
3431 console_lock();
3432 vc->port.tty = NULL;
3433 console_unlock();
3434 }
3435
3436 static void con_cleanup(struct tty_struct *tty)
3437 {
3438 struct vc_data *vc = tty->driver_data;
3439
3440 tty_port_put(&vc->port);
3441 }
3442
3443 static int default_color = 7;
3444 static int default_italic_color = 2;
3445 static int default_underline_color = 3;
3446 module_param_named(color, default_color, int, S_IRUGO | S_IWUSR);
3447 module_param_named(italic, default_italic_color, int, S_IRUGO | S_IWUSR);
3448 module_param_named(underline, default_underline_color, int, S_IRUGO | S_IWUSR);
3449
3450 static void vc_init(struct vc_data *vc, unsigned int rows,
3451 unsigned int cols, int do_clear)
3452 {
3453 int j, k ;
3454
3455 vc->vc_cols = cols;
3456 vc->vc_rows = rows;
3457 vc->vc_size_row = cols << 1;
3458 vc->vc_screenbuf_size = vc->vc_rows * vc->vc_size_row;
3459
3460 set_origin(vc);
3461 vc->vc_pos = vc->vc_origin;
3462 reset_vc(vc);
3463 for (j=k=0; j<16; j++) {
3464 vc->vc_palette[k++] = default_red[j] ;
3465 vc->vc_palette[k++] = default_grn[j] ;
3466 vc->vc_palette[k++] = default_blu[j] ;
3467 }
3468 vc->vc_def_color = default_color;
3469 vc->vc_ulcolor = default_underline_color;
3470 vc->vc_itcolor = default_italic_color;
3471 vc->vc_halfcolor = 0x08;
3472 init_waitqueue_head(&vc->paste_wait);
3473 reset_terminal(vc, do_clear);
3474 }
3475
3476
3477
3478
3479
3480
3481
3482 static int __init con_init(void)
3483 {
3484 const char *display_desc = NULL;
3485 struct vc_data *vc;
3486 unsigned int currcons = 0, i;
3487
3488 console_lock();
3489
3490 if (!conswitchp)
3491 conswitchp = &dummy_con;
3492 display_desc = conswitchp->con_startup();
3493 if (!display_desc) {
3494 fg_console = 0;
3495 console_unlock();
3496 return 0;
3497 }
3498
3499 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3500 struct con_driver *con_driver = ®istered_con_driver[i];
3501
3502 if (con_driver->con == NULL) {
3503 con_driver->con = conswitchp;
3504 con_driver->desc = display_desc;
3505 con_driver->flag = CON_DRIVER_FLAG_INIT;
3506 con_driver->first = 0;
3507 con_driver->last = MAX_NR_CONSOLES - 1;
3508 break;
3509 }
3510 }
3511
3512 for (i = 0; i < MAX_NR_CONSOLES; i++)
3513 con_driver_map[i] = conswitchp;
3514
3515 if (blankinterval) {
3516 blank_state = blank_normal_wait;
3517 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
3518 }
3519
3520 for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
3521 vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
3522 INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
3523 tty_port_init(&vc->port);
3524 visual_init(vc, currcons, 1);
3525
3526 vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
3527 vc_init(vc, vc->vc_rows, vc->vc_cols,
3528 currcons || !vc->vc_sw->con_save_screen);
3529 }
3530 currcons = fg_console = 0;
3531 master_display_fg = vc = vc_cons[currcons].d;
3532 set_origin(vc);
3533 save_screen(vc);
3534 gotoxy(vc, vc->state.x, vc->state.y);
3535 csi_J(vc, 0);
3536 update_screen(vc);
3537 pr_info("Console: %s %s %dx%d\n",
3538 vc->vc_can_do_color ? "colour" : "mono",
3539 display_desc, vc->vc_cols, vc->vc_rows);
3540 printable = 1;
3541
3542 console_unlock();
3543
3544 #ifdef CONFIG_VT_CONSOLE
3545 register_console(&vt_console_driver);
3546 #endif
3547 return 0;
3548 }
3549 console_initcall(con_init);
3550
3551 static const struct tty_operations con_ops = {
3552 .install = con_install,
3553 .open = con_open,
3554 .close = con_close,
3555 .write = con_write,
3556 .write_room = con_write_room,
3557 .put_char = con_put_char,
3558 .flush_chars = con_flush_chars,
3559 .ioctl = vt_ioctl,
3560 #ifdef CONFIG_COMPAT
3561 .compat_ioctl = vt_compat_ioctl,
3562 #endif
3563 .stop = con_stop,
3564 .start = con_start,
3565 .throttle = con_throttle,
3566 .unthrottle = con_unthrottle,
3567 .resize = vt_resize,
3568 .shutdown = con_shutdown,
3569 .cleanup = con_cleanup,
3570 };
3571
3572 static struct cdev vc0_cdev;
3573
3574 static ssize_t show_tty_active(struct device *dev,
3575 struct device_attribute *attr, char *buf)
3576 {
3577 return sprintf(buf, "tty%d\n", fg_console + 1);
3578 }
3579 static DEVICE_ATTR(active, S_IRUGO, show_tty_active, NULL);
3580
3581 static struct attribute *vt_dev_attrs[] = {
3582 &dev_attr_active.attr,
3583 NULL
3584 };
3585
3586 ATTRIBUTE_GROUPS(vt_dev);
3587
3588 int __init vty_init(const struct file_operations *console_fops)
3589 {
3590 cdev_init(&vc0_cdev, console_fops);
3591 if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
3592 register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
3593 panic("Couldn't register /dev/tty0 driver\n");
3594 tty0dev = device_create_with_groups(tty_class, NULL,
3595 MKDEV(TTY_MAJOR, 0), NULL,
3596 vt_dev_groups, "tty0");
3597 if (IS_ERR(tty0dev))
3598 tty0dev = NULL;
3599
3600 vcs_init();
3601
3602 console_driver = tty_alloc_driver(MAX_NR_CONSOLES, TTY_DRIVER_REAL_RAW |
3603 TTY_DRIVER_RESET_TERMIOS);
3604 if (IS_ERR(console_driver))
3605 panic("Couldn't allocate console driver\n");
3606
3607 console_driver->name = "tty";
3608 console_driver->name_base = 1;
3609 console_driver->major = TTY_MAJOR;
3610 console_driver->minor_start = 1;
3611 console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
3612 console_driver->init_termios = tty_std_termios;
3613 if (default_utf8)
3614 console_driver->init_termios.c_iflag |= IUTF8;
3615 tty_set_operations(console_driver, &con_ops);
3616 if (tty_register_driver(console_driver))
3617 panic("Couldn't register console driver\n");
3618 kbd_init();
3619 console_map_init();
3620 #ifdef CONFIG_MDA_CONSOLE
3621 mda_console_init();
3622 #endif
3623 return 0;
3624 }
3625
3626 #ifndef VT_SINGLE_DRIVER
3627
3628 static struct class *vtconsole_class;
3629
3630 static int do_bind_con_driver(const struct consw *csw, int first, int last,
3631 int deflt)
3632 {
3633 struct module *owner = csw->owner;
3634 const char *desc = NULL;
3635 struct con_driver *con_driver;
3636 int i, j = -1, k = -1, retval = -ENODEV;
3637
3638 if (!try_module_get(owner))
3639 return -ENODEV;
3640
3641 WARN_CONSOLE_UNLOCKED();
3642
3643
3644 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3645 con_driver = ®istered_con_driver[i];
3646
3647 if (con_driver->con == csw) {
3648 desc = con_driver->desc;
3649 retval = 0;
3650 break;
3651 }
3652 }
3653
3654 if (retval)
3655 goto err;
3656
3657 if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
3658 csw->con_startup();
3659 con_driver->flag |= CON_DRIVER_FLAG_INIT;
3660 }
3661
3662 if (deflt) {
3663 if (conswitchp)
3664 module_put(conswitchp->owner);
3665
3666 __module_get(owner);
3667 conswitchp = csw;
3668 }
3669
3670 first = max(first, con_driver->first);
3671 last = min(last, con_driver->last);
3672
3673 for (i = first; i <= last; i++) {
3674 int old_was_color;
3675 struct vc_data *vc = vc_cons[i].d;
3676
3677 if (con_driver_map[i])
3678 module_put(con_driver_map[i]->owner);
3679 __module_get(owner);
3680 con_driver_map[i] = csw;
3681
3682 if (!vc || !vc->vc_sw)
3683 continue;
3684
3685 j = i;
3686
3687 if (con_is_visible(vc)) {
3688 k = i;
3689 save_screen(vc);
3690 }
3691
3692 old_was_color = vc->vc_can_do_color;
3693 vc->vc_sw->con_deinit(vc);
3694 vc->vc_origin = (unsigned long)vc->vc_screenbuf;
3695 visual_init(vc, i, 0);
3696 set_origin(vc);
3697 update_attr(vc);
3698
3699
3700
3701
3702
3703 if (old_was_color != vc->vc_can_do_color)
3704 clear_buffer_attributes(vc);
3705 }
3706
3707 pr_info("Console: switching ");
3708 if (!deflt)
3709 pr_cont("consoles %d-%d ", first + 1, last + 1);
3710 if (j >= 0) {
3711 struct vc_data *vc = vc_cons[j].d;
3712
3713 pr_cont("to %s %s %dx%d\n",
3714 vc->vc_can_do_color ? "colour" : "mono",
3715 desc, vc->vc_cols, vc->vc_rows);
3716
3717 if (k >= 0) {
3718 vc = vc_cons[k].d;
3719 update_screen(vc);
3720 }
3721 } else {
3722 pr_cont("to %s\n", desc);
3723 }
3724
3725 retval = 0;
3726 err:
3727 module_put(owner);
3728 return retval;
3729 };
3730
3731
3732 #ifdef CONFIG_VT_HW_CONSOLE_BINDING
3733 int do_unbind_con_driver(const struct consw *csw, int first, int last, int deflt)
3734 {
3735 struct module *owner = csw->owner;
3736 const struct consw *defcsw = NULL;
3737 struct con_driver *con_driver = NULL, *con_back = NULL;
3738 int i, retval = -ENODEV;
3739
3740 if (!try_module_get(owner))
3741 return -ENODEV;
3742
3743 WARN_CONSOLE_UNLOCKED();
3744
3745
3746 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3747 con_driver = ®istered_con_driver[i];
3748
3749 if (con_driver->con == csw &&
3750 con_driver->flag & CON_DRIVER_FLAG_MODULE) {
3751 retval = 0;
3752 break;
3753 }
3754 }
3755
3756 if (retval)
3757 goto err;
3758
3759 retval = -ENODEV;
3760
3761
3762 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3763 con_back = ®istered_con_driver[i];
3764
3765 if (con_back->con && con_back->con != csw) {
3766 defcsw = con_back->con;
3767 retval = 0;
3768 break;
3769 }
3770 }
3771
3772 if (retval)
3773 goto err;
3774
3775 if (!con_is_bound(csw))
3776 goto err;
3777
3778 first = max(first, con_driver->first);
3779 last = min(last, con_driver->last);
3780
3781 for (i = first; i <= last; i++) {
3782 if (con_driver_map[i] == csw) {
3783 module_put(csw->owner);
3784 con_driver_map[i] = NULL;
3785 }
3786 }
3787
3788 if (!con_is_bound(defcsw)) {
3789 const struct consw *defconsw = conswitchp;
3790
3791 defcsw->con_startup();
3792 con_back->flag |= CON_DRIVER_FLAG_INIT;
3793
3794
3795
3796
3797 conswitchp = defconsw;
3798 }
3799
3800 if (!con_is_bound(csw))
3801 con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
3802
3803
3804 do_bind_con_driver(defcsw, first, last, deflt);
3805 err:
3806 module_put(owner);
3807 return retval;
3808
3809 }
3810 EXPORT_SYMBOL_GPL(do_unbind_con_driver);
3811
3812 static int vt_bind(struct con_driver *con)
3813 {
3814 const struct consw *defcsw = NULL, *csw = NULL;
3815 int i, more = 1, first = -1, last = -1, deflt = 0;
3816
3817 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
3818 goto err;
3819
3820 csw = con->con;
3821
3822 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
3823 struct con_driver *con = ®istered_con_driver[i];
3824
3825 if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
3826 defcsw = con->con;
3827 break;
3828 }
3829 }
3830
3831 if (!defcsw)
3832 goto err;
3833
3834 while (more) {
3835 more = 0;
3836
3837 for (i = con->first; i <= con->last; i++) {
3838 if (con_driver_map[i] == defcsw) {
3839 if (first == -1)
3840 first = i;
3841 last = i;
3842 more = 1;
3843 } else if (first != -1)
3844 break;
3845 }
3846
3847 if (first == 0 && last == MAX_NR_CONSOLES -1)
3848 deflt = 1;
3849
3850 if (first != -1)
3851 do_bind_con_driver(csw, first, last, deflt);
3852
3853 first = -1;
3854 last = -1;
3855 deflt = 0;
3856 }
3857
3858 err:
3859 return 0;
3860 }
3861
3862 static int vt_unbind(struct con_driver *con)
3863 {
3864 const struct consw *csw = NULL;
3865 int i, more = 1, first = -1, last = -1, deflt = 0;
3866 int ret;
3867
3868 if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE))
3869 goto err;
3870
3871 csw = con->con;
3872
3873 while (more) {
3874 more = 0;
3875
3876 for (i = con->first; i <= con->last; i++) {
3877 if (con_driver_map[i] == csw) {
3878 if (first == -1)
3879 first = i;
3880 last = i;
3881 more = 1;
3882 } else if (first != -1)
3883 break;
3884 }
3885
3886 if (first == 0 && last == MAX_NR_CONSOLES -1)
3887 deflt = 1;
3888
3889 if (first != -1) {
3890 ret = do_unbind_con_driver(csw, first, last, deflt);
3891 if (ret != 0)
3892 return ret;
3893 }
3894
3895 first = -1;
3896 last = -1;
3897 deflt = 0;
3898 }
3899
3900 err:
3901 return 0;
3902 }
3903 #else
3904 static inline int vt_bind(struct con_driver *con)
3905 {
3906 return 0;
3907 }
3908 static inline int vt_unbind(struct con_driver *con)
3909 {
3910 return 0;
3911 }
3912 #endif
3913
3914 static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
3915 const char *buf, size_t count)
3916 {
3917 struct con_driver *con = dev_get_drvdata(dev);
3918 int bind = simple_strtoul(buf, NULL, 0);
3919
3920 console_lock();
3921
3922 if (bind)
3923 vt_bind(con);
3924 else
3925 vt_unbind(con);
3926
3927 console_unlock();
3928
3929 return count;
3930 }
3931
3932 static ssize_t show_bind(struct device *dev, struct device_attribute *attr,
3933 char *buf)
3934 {
3935 struct con_driver *con = dev_get_drvdata(dev);
3936 int bind;
3937
3938 console_lock();
3939 bind = con_is_bound(con->con);
3940 console_unlock();
3941
3942 return sysfs_emit(buf, "%i\n", bind);
3943 }
3944
3945 static ssize_t show_name(struct device *dev, struct device_attribute *attr,
3946 char *buf)
3947 {
3948 struct con_driver *con = dev_get_drvdata(dev);
3949
3950 return sysfs_emit(buf, "%s %s\n",
3951 (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
3952 con->desc);
3953
3954 }
3955
3956 static DEVICE_ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind);
3957 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
3958
3959 static struct attribute *con_dev_attrs[] = {
3960 &dev_attr_bind.attr,
3961 &dev_attr_name.attr,
3962 NULL
3963 };
3964
3965 ATTRIBUTE_GROUPS(con_dev);
3966
3967 static int vtconsole_init_device(struct con_driver *con)
3968 {
3969 con->flag |= CON_DRIVER_FLAG_ATTR;
3970 return 0;
3971 }
3972
3973 static void vtconsole_deinit_device(struct con_driver *con)
3974 {
3975 con->flag &= ~CON_DRIVER_FLAG_ATTR;
3976 }
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987 int con_is_bound(const struct consw *csw)
3988 {
3989 int i, bound = 0;
3990
3991 WARN_CONSOLE_UNLOCKED();
3992
3993 for (i = 0; i < MAX_NR_CONSOLES; i++) {
3994 if (con_driver_map[i] == csw) {
3995 bound = 1;
3996 break;
3997 }
3998 }
3999
4000 return bound;
4001 }
4002 EXPORT_SYMBOL(con_is_bound);
4003
4004
4005
4006
4007
4008
4009
4010 bool con_is_visible(const struct vc_data *vc)
4011 {
4012 WARN_CONSOLE_UNLOCKED();
4013
4014 return *vc->vc_display_fg == vc;
4015 }
4016 EXPORT_SYMBOL(con_is_visible);
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030 int con_debug_enter(struct vc_data *vc)
4031 {
4032 int ret = 0;
4033
4034 saved_fg_console = fg_console;
4035 saved_last_console = last_console;
4036 saved_want_console = want_console;
4037 saved_vc_mode = vc->vc_mode;
4038 saved_console_blanked = console_blanked;
4039 vc->vc_mode = KD_TEXT;
4040 console_blanked = 0;
4041 if (vc->vc_sw->con_debug_enter)
4042 ret = vc->vc_sw->con_debug_enter(vc);
4043 #ifdef CONFIG_KGDB_KDB
4044
4045 if (vc->vc_rows < 999) {
4046 int linecount;
4047 char lns[4];
4048 const char *setargs[3] = {
4049 "set",
4050 "LINES",
4051 lns,
4052 };
4053 if (kdbgetintenv(setargs[0], &linecount)) {
4054 snprintf(lns, 4, "%i", vc->vc_rows);
4055 kdb_set(2, setargs);
4056 }
4057 }
4058 if (vc->vc_cols < 999) {
4059 int colcount;
4060 char cols[4];
4061 const char *setargs[3] = {
4062 "set",
4063 "COLUMNS",
4064 cols,
4065 };
4066 if (kdbgetintenv(setargs[0], &colcount)) {
4067 snprintf(cols, 4, "%i", vc->vc_cols);
4068 kdb_set(2, setargs);
4069 }
4070 }
4071 #endif
4072 return ret;
4073 }
4074 EXPORT_SYMBOL_GPL(con_debug_enter);
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086 int con_debug_leave(void)
4087 {
4088 struct vc_data *vc;
4089 int ret = 0;
4090
4091 fg_console = saved_fg_console;
4092 last_console = saved_last_console;
4093 want_console = saved_want_console;
4094 console_blanked = saved_console_blanked;
4095 vc_cons[fg_console].d->vc_mode = saved_vc_mode;
4096
4097 vc = vc_cons[fg_console].d;
4098 if (vc->vc_sw->con_debug_leave)
4099 ret = vc->vc_sw->con_debug_leave(vc);
4100 return ret;
4101 }
4102 EXPORT_SYMBOL_GPL(con_debug_leave);
4103
4104 static int do_register_con_driver(const struct consw *csw, int first, int last)
4105 {
4106 struct module *owner = csw->owner;
4107 struct con_driver *con_driver;
4108 const char *desc;
4109 int i, retval;
4110
4111 WARN_CONSOLE_UNLOCKED();
4112
4113 if (!try_module_get(owner))
4114 return -ENODEV;
4115
4116 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
4117 con_driver = ®istered_con_driver[i];
4118
4119
4120 if (con_driver->con == csw) {
4121 retval = -EBUSY;
4122 goto err;
4123 }
4124 }
4125
4126 desc = csw->con_startup();
4127 if (!desc) {
4128 retval = -ENODEV;
4129 goto err;
4130 }
4131
4132 retval = -EINVAL;
4133
4134 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
4135 con_driver = ®istered_con_driver[i];
4136
4137 if (con_driver->con == NULL &&
4138 !(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE)) {
4139 con_driver->con = csw;
4140 con_driver->desc = desc;
4141 con_driver->node = i;
4142 con_driver->flag = CON_DRIVER_FLAG_MODULE |
4143 CON_DRIVER_FLAG_INIT;
4144 con_driver->first = first;
4145 con_driver->last = last;
4146 retval = 0;
4147 break;
4148 }
4149 }
4150
4151 if (retval)
4152 goto err;
4153
4154 con_driver->dev =
4155 device_create_with_groups(vtconsole_class, NULL,
4156 MKDEV(0, con_driver->node),
4157 con_driver, con_dev_groups,
4158 "vtcon%i", con_driver->node);
4159 if (IS_ERR(con_driver->dev)) {
4160 pr_warn("Unable to create device for %s; errno = %ld\n",
4161 con_driver->desc, PTR_ERR(con_driver->dev));
4162 con_driver->dev = NULL;
4163 } else {
4164 vtconsole_init_device(con_driver);
4165 }
4166
4167 err:
4168 module_put(owner);
4169 return retval;
4170 }
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
4181
4182
4183
4184 int do_unregister_con_driver(const struct consw *csw)
4185 {
4186 int i;
4187
4188
4189 if (con_is_bound(csw))
4190 return -EBUSY;
4191
4192 if (csw == conswitchp)
4193 return -EINVAL;
4194
4195 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
4196 struct con_driver *con_driver = ®istered_con_driver[i];
4197
4198 if (con_driver->con == csw) {
4199
4200
4201
4202
4203
4204
4205
4206
4207
4208
4209 con_driver->con = NULL;
4210 con_driver->flag = CON_DRIVER_FLAG_ZOMBIE;
4211 schedule_work(&con_driver_unregister_work);
4212
4213 return 0;
4214 }
4215 }
4216
4217 return -ENODEV;
4218 }
4219 EXPORT_SYMBOL_GPL(do_unregister_con_driver);
4220
4221 static void con_driver_unregister_callback(struct work_struct *ignored)
4222 {
4223 int i;
4224
4225 console_lock();
4226
4227 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
4228 struct con_driver *con_driver = ®istered_con_driver[i];
4229
4230 if (!(con_driver->flag & CON_DRIVER_FLAG_ZOMBIE))
4231 continue;
4232
4233 console_unlock();
4234
4235 vtconsole_deinit_device(con_driver);
4236 device_destroy(vtconsole_class, MKDEV(0, con_driver->node));
4237
4238 console_lock();
4239
4240 if (WARN_ON_ONCE(con_driver->con))
4241 con_driver->con = NULL;
4242 con_driver->desc = NULL;
4243 con_driver->dev = NULL;
4244 con_driver->node = 0;
4245 WARN_ON_ONCE(con_driver->flag != CON_DRIVER_FLAG_ZOMBIE);
4246 con_driver->flag = 0;
4247 con_driver->first = 0;
4248 con_driver->last = 0;
4249 }
4250
4251 console_unlock();
4252 }
4253
4254
4255
4256
4257
4258
4259
4260
4261 int do_take_over_console(const struct consw *csw, int first, int last, int deflt)
4262 {
4263 int err;
4264
4265 err = do_register_con_driver(csw, first, last);
4266
4267
4268
4269
4270
4271 if (err == -EBUSY)
4272 err = 0;
4273 if (!err)
4274 do_bind_con_driver(csw, first, last, deflt);
4275
4276 return err;
4277 }
4278 EXPORT_SYMBOL_GPL(do_take_over_console);
4279
4280
4281
4282
4283
4284
4285 void give_up_console(const struct consw *csw)
4286 {
4287 console_lock();
4288 do_unregister_con_driver(csw);
4289 console_unlock();
4290 }
4291
4292 static int __init vtconsole_class_init(void)
4293 {
4294 int i;
4295
4296 vtconsole_class = class_create(THIS_MODULE, "vtconsole");
4297 if (IS_ERR(vtconsole_class)) {
4298 pr_warn("Unable to create vt console class; errno = %ld\n",
4299 PTR_ERR(vtconsole_class));
4300 vtconsole_class = NULL;
4301 }
4302
4303
4304 for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
4305 struct con_driver *con = ®istered_con_driver[i];
4306
4307 if (con->con && !con->dev) {
4308 con->dev =
4309 device_create_with_groups(vtconsole_class, NULL,
4310 MKDEV(0, con->node),
4311 con, con_dev_groups,
4312 "vtcon%i", con->node);
4313
4314 if (IS_ERR(con->dev)) {
4315 pr_warn("Unable to create device for %s; errno = %ld\n",
4316 con->desc, PTR_ERR(con->dev));
4317 con->dev = NULL;
4318 } else {
4319 vtconsole_init_device(con);
4320 }
4321 }
4322 }
4323
4324 return 0;
4325 }
4326 postcore_initcall(vtconsole_class_init);
4327
4328 #endif
4329
4330
4331
4332
4333
4334 static int set_vesa_blanking(char __user *p)
4335 {
4336 unsigned int mode;
4337
4338 if (get_user(mode, p + 1))
4339 return -EFAULT;
4340
4341 vesa_blank_mode = (mode < 4) ? mode : 0;
4342 return 0;
4343 }
4344
4345 void do_blank_screen(int entering_gfx)
4346 {
4347 struct vc_data *vc = vc_cons[fg_console].d;
4348 int i;
4349
4350 might_sleep();
4351
4352 WARN_CONSOLE_UNLOCKED();
4353
4354 if (console_blanked) {
4355 if (blank_state == blank_vesa_wait) {
4356 blank_state = blank_off;
4357 vc->vc_sw->con_blank(vc, vesa_blank_mode + 1, 0);
4358 }
4359 return;
4360 }
4361
4362
4363 if (entering_gfx) {
4364 hide_cursor(vc);
4365 save_screen(vc);
4366 vc->vc_sw->con_blank(vc, -1, 1);
4367 console_blanked = fg_console + 1;
4368 blank_state = blank_off;
4369 set_origin(vc);
4370 return;
4371 }
4372
4373 blank_state = blank_off;
4374
4375
4376 if (vc->vc_mode != KD_TEXT) {
4377 console_blanked = fg_console + 1;
4378 return;
4379 }
4380
4381 hide_cursor(vc);
4382 del_timer_sync(&console_timer);
4383 blank_timer_expired = 0;
4384
4385 save_screen(vc);
4386
4387 i = vc->vc_sw->con_blank(vc, vesa_off_interval ? 1 : (vesa_blank_mode + 1), 0);
4388 console_blanked = fg_console + 1;
4389 if (i)
4390 set_origin(vc);
4391
4392 if (console_blank_hook && console_blank_hook(1))
4393 return;
4394
4395 if (vesa_off_interval && vesa_blank_mode) {
4396 blank_state = blank_vesa_wait;
4397 mod_timer(&console_timer, jiffies + vesa_off_interval);
4398 }
4399 vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
4400 }
4401 EXPORT_SYMBOL(do_blank_screen);
4402
4403
4404
4405
4406 void do_unblank_screen(int leaving_gfx)
4407 {
4408 struct vc_data *vc;
4409
4410
4411
4412
4413
4414 if (!oops_in_progress)
4415 might_sleep();
4416
4417 WARN_CONSOLE_UNLOCKED();
4418
4419 ignore_poke = 0;
4420 if (!console_blanked)
4421 return;
4422 if (!vc_cons_allocated(fg_console)) {
4423
4424 pr_warn("unblank_screen: tty %d not allocated ??\n",
4425 fg_console + 1);
4426 return;
4427 }
4428 vc = vc_cons[fg_console].d;
4429 if (vc->vc_mode != KD_TEXT)
4430 return;
4431
4432 if (blankinterval) {
4433 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
4434 blank_state = blank_normal_wait;
4435 }
4436
4437 console_blanked = 0;
4438 if (vc->vc_sw->con_blank(vc, 0, leaving_gfx))
4439
4440 update_screen(vc);
4441 if (console_blank_hook)
4442 console_blank_hook(0);
4443 set_palette(vc);
4444 set_cursor(vc);
4445 vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
4446 }
4447 EXPORT_SYMBOL(do_unblank_screen);
4448
4449
4450
4451
4452
4453
4454
4455 void unblank_screen(void)
4456 {
4457 do_unblank_screen(0);
4458 }
4459
4460
4461
4462
4463
4464
4465 static void blank_screen_t(struct timer_list *unused)
4466 {
4467 blank_timer_expired = 1;
4468 schedule_work(&console_work);
4469 }
4470
4471 void poke_blanked_console(void)
4472 {
4473 WARN_CONSOLE_UNLOCKED();
4474
4475
4476
4477
4478
4479
4480
4481 might_sleep();
4482
4483
4484
4485
4486 del_timer(&console_timer);
4487 blank_timer_expired = 0;
4488
4489 if (ignore_poke || !vc_cons[fg_console].d || vc_cons[fg_console].d->vc_mode == KD_GRAPHICS)
4490 return;
4491 if (console_blanked)
4492 unblank_screen();
4493 else if (blankinterval) {
4494 mod_timer(&console_timer, jiffies + (blankinterval * HZ));
4495 blank_state = blank_normal_wait;
4496 }
4497 }
4498
4499
4500
4501
4502
4503 static void set_palette(struct vc_data *vc)
4504 {
4505 WARN_CONSOLE_UNLOCKED();
4506
4507 if (vc->vc_mode != KD_GRAPHICS && vc->vc_sw->con_set_palette)
4508 vc->vc_sw->con_set_palette(vc, color_table);
4509 }
4510
4511
4512
4513
4514
4515
4516 int con_set_cmap(unsigned char __user *arg)
4517 {
4518 int i, j, k;
4519 unsigned char colormap[3*16];
4520
4521 if (copy_from_user(colormap, arg, sizeof(colormap)))
4522 return -EFAULT;
4523
4524 console_lock();
4525 for (i = k = 0; i < 16; i++) {
4526 default_red[i] = colormap[k++];
4527 default_grn[i] = colormap[k++];
4528 default_blu[i] = colormap[k++];
4529 }
4530 for (i = 0; i < MAX_NR_CONSOLES; i++) {
4531 if (!vc_cons_allocated(i))
4532 continue;
4533 for (j = k = 0; j < 16; j++) {
4534 vc_cons[i].d->vc_palette[k++] = default_red[j];
4535 vc_cons[i].d->vc_palette[k++] = default_grn[j];
4536 vc_cons[i].d->vc_palette[k++] = default_blu[j];
4537 }
4538 set_palette(vc_cons[i].d);
4539 }
4540 console_unlock();
4541
4542 return 0;
4543 }
4544
4545 int con_get_cmap(unsigned char __user *arg)
4546 {
4547 int i, k;
4548 unsigned char colormap[3*16];
4549
4550 console_lock();
4551 for (i = k = 0; i < 16; i++) {
4552 colormap[k++] = default_red[i];
4553 colormap[k++] = default_grn[i];
4554 colormap[k++] = default_blu[i];
4555 }
4556 console_unlock();
4557
4558 if (copy_to_user(arg, colormap, sizeof(colormap)))
4559 return -EFAULT;
4560
4561 return 0;
4562 }
4563
4564 void reset_palette(struct vc_data *vc)
4565 {
4566 int j, k;
4567 for (j=k=0; j<16; j++) {
4568 vc->vc_palette[k++] = default_red[j];
4569 vc->vc_palette[k++] = default_grn[j];
4570 vc->vc_palette[k++] = default_blu[j];
4571 }
4572 set_palette(vc);
4573 }
4574
4575
4576
4577
4578
4579
4580
4581
4582
4583
4584
4585
4586
4587
4588 #define max_font_size 65536
4589
4590 static int con_font_get(struct vc_data *vc, struct console_font_op *op)
4591 {
4592 struct console_font font;
4593 int rc = -EINVAL;
4594 int c;
4595
4596 if (op->data) {
4597 font.data = kmalloc(max_font_size, GFP_KERNEL);
4598 if (!font.data)
4599 return -ENOMEM;
4600 } else
4601 font.data = NULL;
4602
4603 console_lock();
4604 if (vc->vc_mode != KD_TEXT)
4605 rc = -EINVAL;
4606 else if (vc->vc_sw->con_font_get)
4607 rc = vc->vc_sw->con_font_get(vc, &font);
4608 else
4609 rc = -ENOSYS;
4610 console_unlock();
4611
4612 if (rc)
4613 goto out;
4614
4615 c = (font.width+7)/8 * 32 * font.charcount;
4616
4617 if (op->data && font.charcount > op->charcount)
4618 rc = -ENOSPC;
4619 if (font.width > op->width || font.height > op->height)
4620 rc = -ENOSPC;
4621 if (rc)
4622 goto out;
4623
4624 op->height = font.height;
4625 op->width = font.width;
4626 op->charcount = font.charcount;
4627
4628 if (op->data && copy_to_user(op->data, font.data, c))
4629 rc = -EFAULT;
4630
4631 out:
4632 kfree(font.data);
4633 return rc;
4634 }
4635
4636 static int con_font_set(struct vc_data *vc, struct console_font_op *op)
4637 {
4638 struct console_font font;
4639 int rc = -EINVAL;
4640 int size;
4641
4642 if (vc->vc_mode != KD_TEXT)
4643 return -EINVAL;
4644 if (!op->data)
4645 return -EINVAL;
4646 if (op->charcount > 512)
4647 return -EINVAL;
4648 if (op->width <= 0 || op->width > 32 || !op->height || op->height > 32)
4649 return -EINVAL;
4650 size = (op->width+7)/8 * 32 * op->charcount;
4651 if (size > max_font_size)
4652 return -ENOSPC;
4653
4654 font.data = memdup_user(op->data, size);
4655 if (IS_ERR(font.data))
4656 return PTR_ERR(font.data);
4657
4658 font.charcount = op->charcount;
4659 font.width = op->width;
4660 font.height = op->height;
4661
4662 console_lock();
4663 if (vc->vc_mode != KD_TEXT)
4664 rc = -EINVAL;
4665 else if (vc->vc_sw->con_font_set) {
4666 if (vc_is_sel(vc))
4667 clear_selection();
4668 rc = vc->vc_sw->con_font_set(vc, &font, op->flags);
4669 } else
4670 rc = -ENOSYS;
4671 console_unlock();
4672 kfree(font.data);
4673 return rc;
4674 }
4675
4676 static int con_font_default(struct vc_data *vc, struct console_font_op *op)
4677 {
4678 struct console_font font = {.width = op->width, .height = op->height};
4679 char name[MAX_FONT_NAME];
4680 char *s = name;
4681 int rc;
4682
4683
4684 if (!op->data)
4685 s = NULL;
4686 else if (strncpy_from_user(name, op->data, MAX_FONT_NAME - 1) < 0)
4687 return -EFAULT;
4688 else
4689 name[MAX_FONT_NAME - 1] = 0;
4690
4691 console_lock();
4692 if (vc->vc_mode != KD_TEXT) {
4693 console_unlock();
4694 return -EINVAL;
4695 }
4696 if (vc->vc_sw->con_font_default) {
4697 if (vc_is_sel(vc))
4698 clear_selection();
4699 rc = vc->vc_sw->con_font_default(vc, &font, s);
4700 } else
4701 rc = -ENOSYS;
4702 console_unlock();
4703 if (!rc) {
4704 op->width = font.width;
4705 op->height = font.height;
4706 }
4707 return rc;
4708 }
4709
4710 int con_font_op(struct vc_data *vc, struct console_font_op *op)
4711 {
4712 switch (op->op) {
4713 case KD_FONT_OP_SET:
4714 return con_font_set(vc, op);
4715 case KD_FONT_OP_GET:
4716 return con_font_get(vc, op);
4717 case KD_FONT_OP_SET_DEFAULT:
4718 return con_font_default(vc, op);
4719 case KD_FONT_OP_COPY:
4720
4721 return -EINVAL;
4722 }
4723 return -ENOSYS;
4724 }
4725
4726
4727
4728
4729
4730
4731 u16 screen_glyph(const struct vc_data *vc, int offset)
4732 {
4733 u16 w = scr_readw(screenpos(vc, offset, true));
4734 u16 c = w & 0xff;
4735
4736 if (w & vc->vc_hi_font_mask)
4737 c |= 0x100;
4738 return c;
4739 }
4740 EXPORT_SYMBOL_GPL(screen_glyph);
4741
4742 u32 screen_glyph_unicode(const struct vc_data *vc, int n)
4743 {
4744 struct uni_screen *uniscr = get_vc_uniscr(vc);
4745
4746 if (uniscr)
4747 return uniscr->lines[n / vc->vc_cols][n % vc->vc_cols];
4748 return inverse_translate(vc, screen_glyph(vc, n * 2), true);
4749 }
4750 EXPORT_SYMBOL_GPL(screen_glyph_unicode);
4751
4752
4753 unsigned short *screen_pos(const struct vc_data *vc, int w_offset, bool viewed)
4754 {
4755 return screenpos(vc, 2 * w_offset, viewed);
4756 }
4757 EXPORT_SYMBOL_GPL(screen_pos);
4758
4759 void getconsxy(const struct vc_data *vc, unsigned char xy[static 2])
4760 {
4761
4762 xy[0] = min(vc->state.x, 0xFFu);
4763 xy[1] = min(vc->state.y, 0xFFu);
4764 }
4765
4766 void putconsxy(struct vc_data *vc, unsigned char xy[static const 2])
4767 {
4768 hide_cursor(vc);
4769 gotoxy(vc, xy[0], xy[1]);
4770 set_cursor(vc);
4771 }
4772
4773 u16 vcs_scr_readw(const struct vc_data *vc, const u16 *org)
4774 {
4775 if ((unsigned long)org == vc->vc_pos && softcursor_original != -1)
4776 return softcursor_original;
4777 return scr_readw(org);
4778 }
4779
4780 void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org)
4781 {
4782 scr_writew(val, org);
4783 if ((unsigned long)org == vc->vc_pos) {
4784 softcursor_original = -1;
4785 add_softcursor(vc);
4786 }
4787 }
4788
4789 void vcs_scr_updated(struct vc_data *vc)
4790 {
4791 notify_update(vc);
4792 }
4793
4794 void vc_scrolldelta_helper(struct vc_data *c, int lines,
4795 unsigned int rolled_over, void *base, unsigned int size)
4796 {
4797 unsigned long ubase = (unsigned long)base;
4798 ptrdiff_t scr_end = (void *)c->vc_scr_end - base;
4799 ptrdiff_t vorigin = (void *)c->vc_visible_origin - base;
4800 ptrdiff_t origin = (void *)c->vc_origin - base;
4801 int margin = c->vc_size_row * 4;
4802 int from, wrap, from_off, avail;
4803
4804
4805 if (!lines) {
4806 c->vc_visible_origin = c->vc_origin;
4807 return;
4808 }
4809
4810
4811 if (rolled_over > scr_end + margin) {
4812 from = scr_end;
4813 wrap = rolled_over + c->vc_size_row;
4814 } else {
4815 from = 0;
4816 wrap = size;
4817 }
4818
4819 from_off = (vorigin - from + wrap) % wrap + lines * c->vc_size_row;
4820 avail = (origin - from + wrap) % wrap;
4821
4822
4823 if (avail < 2 * margin)
4824 margin = 0;
4825 if (from_off < margin)
4826 from_off = 0;
4827 if (from_off > avail - margin)
4828 from_off = avail;
4829
4830 c->vc_visible_origin = ubase + (from + from_off) % wrap;
4831 }
4832 EXPORT_SYMBOL_GPL(vc_scrolldelta_helper);
4833
4834
4835
4836
4837
4838 EXPORT_SYMBOL(color_table);
4839 EXPORT_SYMBOL(default_red);
4840 EXPORT_SYMBOL(default_grn);
4841 EXPORT_SYMBOL(default_blu);
4842 EXPORT_SYMBOL(update_region);
4843 EXPORT_SYMBOL(redraw_screen);
4844 EXPORT_SYMBOL(vc_resize);
4845 EXPORT_SYMBOL(fg_console);
4846 EXPORT_SYMBOL(console_blank_hook);
4847 EXPORT_SYMBOL(console_blanked);
4848 EXPORT_SYMBOL(vc_cons);
4849 EXPORT_SYMBOL(global_cursor_default);
4850 #ifndef VT_SINGLE_DRIVER
4851 EXPORT_SYMBOL(give_up_console);
4852 #endif