diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/tty/vt | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/consolemap.c | 178 | ||||
-rw-r--r-- | drivers/tty/vt/keyboard.c | 848 | ||||
-rw-r--r-- | drivers/tty/vt/selection.c | 65 | ||||
-rw-r--r-- | drivers/tty/vt/vc_screen.c | 5 | ||||
-rw-r--r-- | drivers/tty/vt/vt.c | 299 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 523 |
6 files changed, 711 insertions, 1207 deletions
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 248381b3072..45d3e80156d 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/tty.h> | 20 | #include <linux/tty.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | #include <linux/console.h> | ||
23 | #include <linux/consolemap.h> | 22 | #include <linux/consolemap.h> |
24 | #include <linux/vt_kern.h> | 23 | #include <linux/vt_kern.h> |
25 | 24 | ||
@@ -313,7 +312,6 @@ int con_set_trans_old(unsigned char __user * arg) | |||
313 | if (!access_ok(VERIFY_READ, arg, E_TABSZ)) | 312 | if (!access_ok(VERIFY_READ, arg, E_TABSZ)) |
314 | return -EFAULT; | 313 | return -EFAULT; |
315 | 314 | ||
316 | console_lock(); | ||
317 | for (i=0; i<E_TABSZ ; i++) { | 315 | for (i=0; i<E_TABSZ ; i++) { |
318 | unsigned char uc; | 316 | unsigned char uc; |
319 | __get_user(uc, arg+i); | 317 | __get_user(uc, arg+i); |
@@ -321,7 +319,6 @@ int con_set_trans_old(unsigned char __user * arg) | |||
321 | } | 319 | } |
322 | 320 | ||
323 | update_user_maps(); | 321 | update_user_maps(); |
324 | console_unlock(); | ||
325 | return 0; | 322 | return 0; |
326 | } | 323 | } |
327 | 324 | ||
@@ -333,13 +330,11 @@ int con_get_trans_old(unsigned char __user * arg) | |||
333 | if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) | 330 | if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) |
334 | return -EFAULT; | 331 | return -EFAULT; |
335 | 332 | ||
336 | console_lock(); | ||
337 | for (i=0; i<E_TABSZ ; i++) | 333 | for (i=0; i<E_TABSZ ; i++) |
338 | { | 334 | { |
339 | ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); | 335 | ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); |
340 | __put_user((ch & ~0xff) ? 0 : ch, arg+i); | 336 | __put_user((ch & ~0xff) ? 0 : ch, arg+i); |
341 | } | 337 | } |
342 | console_unlock(); | ||
343 | return 0; | 338 | return 0; |
344 | } | 339 | } |
345 | 340 | ||
@@ -351,7 +346,6 @@ int con_set_trans_new(ushort __user * arg) | |||
351 | if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) | 346 | if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) |
352 | return -EFAULT; | 347 | return -EFAULT; |
353 | 348 | ||
354 | console_lock(); | ||
355 | for (i=0; i<E_TABSZ ; i++) { | 349 | for (i=0; i<E_TABSZ ; i++) { |
356 | unsigned short us; | 350 | unsigned short us; |
357 | __get_user(us, arg+i); | 351 | __get_user(us, arg+i); |
@@ -359,7 +353,6 @@ int con_set_trans_new(ushort __user * arg) | |||
359 | } | 353 | } |
360 | 354 | ||
361 | update_user_maps(); | 355 | update_user_maps(); |
362 | console_unlock(); | ||
363 | return 0; | 356 | return 0; |
364 | } | 357 | } |
365 | 358 | ||
@@ -371,10 +364,8 @@ int con_get_trans_new(ushort __user * arg) | |||
371 | if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) | 364 | if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) |
372 | return -EFAULT; | 365 | return -EFAULT; |
373 | 366 | ||
374 | console_lock(); | ||
375 | for (i=0; i<E_TABSZ ; i++) | 367 | for (i=0; i<E_TABSZ ; i++) |
376 | __put_user(p[i], arg+i); | 368 | __put_user(p[i], arg+i); |
377 | console_unlock(); | ||
378 | 369 | ||
379 | return 0; | 370 | return 0; |
380 | } | 371 | } |
@@ -410,11 +401,12 @@ static void con_release_unimap(struct uni_pagedir *p) | |||
410 | kfree(p->inverse_translations[i]); | 401 | kfree(p->inverse_translations[i]); |
411 | p->inverse_translations[i] = NULL; | 402 | p->inverse_translations[i] = NULL; |
412 | } | 403 | } |
413 | kfree(p->inverse_trans_unicode); | 404 | if (p->inverse_trans_unicode) { |
414 | p->inverse_trans_unicode = NULL; | 405 | kfree(p->inverse_trans_unicode); |
406 | p->inverse_trans_unicode = NULL; | ||
407 | } | ||
415 | } | 408 | } |
416 | 409 | ||
417 | /* Caller must hold the console lock */ | ||
418 | void con_free_unimap(struct vc_data *vc) | 410 | void con_free_unimap(struct vc_data *vc) |
419 | { | 411 | { |
420 | struct uni_pagedir *p; | 412 | struct uni_pagedir *p; |
@@ -495,21 +487,17 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) | |||
495 | return 0; | 487 | return 0; |
496 | } | 488 | } |
497 | 489 | ||
498 | /* ui is a leftover from using a hashtable, but might be used again | 490 | /* ui is a leftover from using a hashtable, but might be used again */ |
499 | Caller must hold the lock */ | 491 | int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) |
500 | static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) | ||
501 | { | 492 | { |
502 | struct uni_pagedir *p, *q; | 493 | struct uni_pagedir *p, *q; |
503 | 494 | ||
504 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 495 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
505 | if (p && p->readonly) | 496 | if (p && p->readonly) return -EIO; |
506 | return -EIO; | ||
507 | |||
508 | if (!p || --p->refcount) { | 497 | if (!p || --p->refcount) { |
509 | q = kzalloc(sizeof(*p), GFP_KERNEL); | 498 | q = kzalloc(sizeof(*p), GFP_KERNEL); |
510 | if (!q) { | 499 | if (!q) { |
511 | if (p) | 500 | if (p) p->refcount++; |
512 | p->refcount++; | ||
513 | return -ENOMEM; | 501 | return -ENOMEM; |
514 | } | 502 | } |
515 | q->refcount=1; | 503 | q->refcount=1; |
@@ -523,96 +511,43 @@ static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui) | |||
523 | return 0; | 511 | return 0; |
524 | } | 512 | } |
525 | 513 | ||
526 | int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) | ||
527 | { | ||
528 | int ret; | ||
529 | console_lock(); | ||
530 | ret = con_do_clear_unimap(vc, ui); | ||
531 | console_unlock(); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) | 514 | int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) |
536 | { | 515 | { |
537 | int err = 0, err1, i; | 516 | int err = 0, err1, i; |
538 | struct uni_pagedir *p, *q; | 517 | struct uni_pagedir *p, *q; |
539 | 518 | ||
540 | console_lock(); | ||
541 | |||
542 | /* Save original vc_unipagdir_loc in case we allocate a new one */ | ||
543 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 519 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
544 | if (p->readonly) { | 520 | if (p->readonly) return -EIO; |
545 | console_unlock(); | ||
546 | return -EIO; | ||
547 | } | ||
548 | 521 | ||
549 | if (!ct) { | 522 | if (!ct) return 0; |
550 | console_unlock(); | ||
551 | return 0; | ||
552 | } | ||
553 | 523 | ||
554 | if (p->refcount > 1) { | 524 | if (p->refcount > 1) { |
555 | int j, k; | 525 | int j, k; |
556 | u16 **p1, *p2, l; | 526 | u16 **p1, *p2, l; |
557 | 527 | ||
558 | err1 = con_do_clear_unimap(vc, NULL); | 528 | err1 = con_clear_unimap(vc, NULL); |
559 | if (err1) { | 529 | if (err1) return err1; |
560 | console_unlock(); | ||
561 | return err1; | ||
562 | } | ||
563 | 530 | ||
564 | /* | ||
565 | * Since refcount was > 1, con_clear_unimap() allocated a | ||
566 | * a new uni_pagedir for this vc. Re: p != q | ||
567 | */ | ||
568 | q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 531 | q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
569 | 532 | for (i = 0, l = 0; i < 32; i++) | |
570 | /* | ||
571 | * uni_pgdir is a 32*32*64 table with rows allocated | ||
572 | * when its first entry is added. The unicode value must | ||
573 | * still be incremented for empty rows. We are copying | ||
574 | * entries from "p" (old) to "q" (new). | ||
575 | */ | ||
576 | l = 0; /* unicode value */ | ||
577 | for (i = 0; i < 32; i++) | ||
578 | if ((p1 = p->uni_pgdir[i])) | 533 | if ((p1 = p->uni_pgdir[i])) |
579 | for (j = 0; j < 32; j++) | 534 | for (j = 0; j < 32; j++) |
580 | if ((p2 = p1[j])) { | 535 | if ((p2 = p1[j])) |
581 | for (k = 0; k < 64; k++, l++) | 536 | for (k = 0; k < 64; k++, l++) |
582 | if (p2[k] != 0xffff) { | 537 | if (p2[k] != 0xffff) { |
583 | /* | ||
584 | * Found one, copy entry for unicode | ||
585 | * l with fontpos value p2[k]. | ||
586 | */ | ||
587 | err1 = con_insert_unipair(q, l, p2[k]); | 538 | err1 = con_insert_unipair(q, l, p2[k]); |
588 | if (err1) { | 539 | if (err1) { |
589 | p->refcount++; | 540 | p->refcount++; |
590 | *vc->vc_uni_pagedir_loc = (unsigned long)p; | 541 | *vc->vc_uni_pagedir_loc = (unsigned long)p; |
591 | con_release_unimap(q); | 542 | con_release_unimap(q); |
592 | kfree(q); | 543 | kfree(q); |
593 | console_unlock(); | ||
594 | return err1; | 544 | return err1; |
595 | } | 545 | } |
596 | } | 546 | } |
597 | } else { | 547 | p = q; |
598 | /* Account for row of 64 empty entries */ | 548 | } else if (p == dflt) |
599 | l += 64; | ||
600 | } | ||
601 | else | ||
602 | /* Account for empty table */ | ||
603 | l += 32 * 64; | ||
604 | |||
605 | /* | ||
606 | * Finished copying font table, set vc_uni_pagedir to new table | ||
607 | */ | ||
608 | p = q; | ||
609 | } else if (p == dflt) { | ||
610 | dflt = NULL; | 549 | dflt = NULL; |
611 | } | 550 | |
612 | |||
613 | /* | ||
614 | * Insert user specified unicode pairs into new table. | ||
615 | */ | ||
616 | while (ct--) { | 551 | while (ct--) { |
617 | unsigned short unicode, fontpos; | 552 | unsigned short unicode, fontpos; |
618 | __get_user(unicode, &list->unicode); | 553 | __get_user(unicode, &list->unicode); |
@@ -622,33 +557,21 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) | |||
622 | list++; | 557 | list++; |
623 | } | 558 | } |
624 | 559 | ||
625 | /* | 560 | if (con_unify_unimap(vc, p)) |
626 | * Merge with fontmaps of any other virtual consoles. | ||
627 | */ | ||
628 | if (con_unify_unimap(vc, p)) { | ||
629 | console_unlock(); | ||
630 | return err; | 561 | return err; |
631 | } | ||
632 | 562 | ||
633 | for (i = 0; i <= 3; i++) | 563 | for (i = 0; i <= 3; i++) |
634 | set_inverse_transl(vc, p, i); /* Update inverse translations */ | 564 | set_inverse_transl(vc, p, i); /* Update all inverse translations */ |
635 | set_inverse_trans_unicode(vc, p); | 565 | set_inverse_trans_unicode(vc, p); |
636 | 566 | ||
637 | console_unlock(); | ||
638 | return err; | 567 | return err; |
639 | } | 568 | } |
640 | 569 | ||
641 | /** | 570 | /* Loads the unimap for the hardware font, as defined in uni_hash.tbl. |
642 | * con_set_default_unimap - set default unicode map | 571 | The representation used was the most compact I could come up |
643 | * @vc: the console we are updating | 572 | with. This routine is executed at sys_setup time, and when the |
644 | * | 573 | PIO_FONTRESET ioctl is called. */ |
645 | * Loads the unimap for the hardware font, as defined in uni_hash.tbl. | 574 | |
646 | * The representation used was the most compact I could come up | ||
647 | * with. This routine is executed at video setup, and when the | ||
648 | * PIO_FONTRESET ioctl is called. | ||
649 | * | ||
650 | * The caller must hold the console lock | ||
651 | */ | ||
652 | int con_set_default_unimap(struct vc_data *vc) | 575 | int con_set_default_unimap(struct vc_data *vc) |
653 | { | 576 | { |
654 | int i, j, err = 0, err1; | 577 | int i, j, err = 0, err1; |
@@ -659,10 +582,9 @@ int con_set_default_unimap(struct vc_data *vc) | |||
659 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 582 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
660 | if (p == dflt) | 583 | if (p == dflt) |
661 | return 0; | 584 | return 0; |
662 | |||
663 | dflt->refcount++; | 585 | dflt->refcount++; |
664 | *vc->vc_uni_pagedir_loc = (unsigned long)dflt; | 586 | *vc->vc_uni_pagedir_loc = (unsigned long)dflt; |
665 | if (p && !--p->refcount) { | 587 | if (p && --p->refcount) { |
666 | con_release_unimap(p); | 588 | con_release_unimap(p); |
667 | kfree(p); | 589 | kfree(p); |
668 | } | 590 | } |
@@ -671,9 +593,8 @@ int con_set_default_unimap(struct vc_data *vc) | |||
671 | 593 | ||
672 | /* The default font is always 256 characters */ | 594 | /* The default font is always 256 characters */ |
673 | 595 | ||
674 | err = con_do_clear_unimap(vc, NULL); | 596 | err = con_clear_unimap(vc, NULL); |
675 | if (err) | 597 | if (err) return err; |
676 | return err; | ||
677 | 598 | ||
678 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 599 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
679 | q = dfont_unitable; | 600 | q = dfont_unitable; |
@@ -698,13 +619,6 @@ int con_set_default_unimap(struct vc_data *vc) | |||
698 | } | 619 | } |
699 | EXPORT_SYMBOL(con_set_default_unimap); | 620 | EXPORT_SYMBOL(con_set_default_unimap); |
700 | 621 | ||
701 | /** | ||
702 | * con_copy_unimap - copy unimap between two vts | ||
703 | * @dst_vc: target | ||
704 | * @src_vt: source | ||
705 | * | ||
706 | * The caller must hold the console lock when invoking this method | ||
707 | */ | ||
708 | int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) | 622 | int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) |
709 | { | 623 | { |
710 | struct uni_pagedir *q; | 624 | struct uni_pagedir *q; |
@@ -719,23 +633,13 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) | |||
719 | *dst_vc->vc_uni_pagedir_loc = (long)q; | 633 | *dst_vc->vc_uni_pagedir_loc = (long)q; |
720 | return 0; | 634 | return 0; |
721 | } | 635 | } |
722 | EXPORT_SYMBOL(con_copy_unimap); | ||
723 | 636 | ||
724 | /** | ||
725 | * con_get_unimap - get the unicode map | ||
726 | * @vc: the console to read from | ||
727 | * | ||
728 | * Read the console unicode data for this console. Called from the ioctl | ||
729 | * handlers. | ||
730 | */ | ||
731 | int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) | 637 | int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) |
732 | { | 638 | { |
733 | int i, j, k, ect; | 639 | int i, j, k, ect; |
734 | u16 **p1, *p2; | 640 | u16 **p1, *p2; |
735 | struct uni_pagedir *p; | 641 | struct uni_pagedir *p; |
736 | 642 | ||
737 | console_lock(); | ||
738 | |||
739 | ect = 0; | 643 | ect = 0; |
740 | if (*vc->vc_uni_pagedir_loc) { | 644 | if (*vc->vc_uni_pagedir_loc) { |
741 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | 645 | p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; |
@@ -755,19 +659,22 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni | |||
755 | } | 659 | } |
756 | } | 660 | } |
757 | __put_user(ect, uct); | 661 | __put_user(ect, uct); |
758 | console_unlock(); | ||
759 | return ((ect <= ct) ? 0 : -ENOMEM); | 662 | return ((ect <= ct) ? 0 : -ENOMEM); |
760 | } | 663 | } |
761 | 664 | ||
665 | void con_protect_unimap(struct vc_data *vc, int rdonly) | ||
666 | { | ||
667 | struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; | ||
668 | |||
669 | if (p) | ||
670 | p->readonly = rdonly; | ||
671 | } | ||
672 | |||
762 | /* | 673 | /* |
763 | * Always use USER_MAP. These functions are used by the keyboard, | 674 | * Always use USER_MAP. These functions are used by the keyboard, |
764 | * which shouldn't be affected by G0/G1 switching, etc. | 675 | * which shouldn't be affected by G0/G1 switching, etc. |
765 | * If the user map still contains default values, i.e. the | 676 | * If the user map still contains default values, i.e. the |
766 | * direct-to-font mapping, then assume user is using Latin1. | 677 | * direct-to-font mapping, then assume user is using Latin1. |
767 | * | ||
768 | * FIXME: at some point we need to decide if we want to lock the table | ||
769 | * update element itself via the keyboard_event_lock for consistency with the | ||
770 | * keyboard driver as well as the consoles | ||
771 | */ | 678 | */ |
772 | /* may be called during an interrupt */ | 679 | /* may be called during an interrupt */ |
773 | u32 conv_8bit_to_uni(unsigned char c) | 680 | u32 conv_8bit_to_uni(unsigned char c) |
@@ -835,3 +742,4 @@ console_map_init(void) | |||
835 | con_set_default_unimap(vc_cons[i].d); | 742 | con_set_default_unimap(vc_cons[i].d); |
836 | } | 743 | } |
837 | 744 | ||
745 | EXPORT_SYMBOL(con_copy_unimap); | ||
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index 681765baef6..3761ccf0f34 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/irq.h> | ||
36 | 37 | ||
37 | #include <linux/kbd_kern.h> | 38 | #include <linux/kbd_kern.h> |
38 | #include <linux/kbd_diacr.h> | 39 | #include <linux/kbd_diacr.h> |
@@ -41,9 +42,6 @@ | |||
41 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
42 | #include <linux/notifier.h> | 43 | #include <linux/notifier.h> |
43 | #include <linux/jiffies.h> | 44 | #include <linux/jiffies.h> |
44 | #include <linux/uaccess.h> | ||
45 | |||
46 | #include <asm/irq_regs.h> | ||
47 | 45 | ||
48 | extern void ctrl_alt_del(void); | 46 | extern void ctrl_alt_del(void); |
49 | 47 | ||
@@ -53,17 +51,23 @@ extern void ctrl_alt_del(void); | |||
53 | 51 | ||
54 | #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) | 52 | #define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) |
55 | 53 | ||
56 | #if defined(CONFIG_X86) || defined(CONFIG_PARISC) | 54 | /* |
57 | #include <asm/kbdleds.h> | 55 | * Some laptops take the 789uiojklm,. keys as number pad when NumLock is on. |
56 | * This seems a good reason to start with NumLock off. On HIL keyboards | ||
57 | * of PARISC machines however there is no NumLock key and everyone expects the keypad | ||
58 | * to be used for numbers. | ||
59 | */ | ||
60 | |||
61 | #if defined(CONFIG_PARISC) && (defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)) | ||
62 | #define KBD_DEFLEDS (1 << VC_NUMLOCK) | ||
58 | #else | 63 | #else |
59 | static inline int kbd_defleds(void) | 64 | #define KBD_DEFLEDS 0 |
60 | { | ||
61 | return 0; | ||
62 | } | ||
63 | #endif | 65 | #endif |
64 | 66 | ||
65 | #define KBD_DEFLOCK 0 | 67 | #define KBD_DEFLOCK 0 |
66 | 68 | ||
69 | void compute_shiftstate(void); | ||
70 | |||
67 | /* | 71 | /* |
68 | * Handler Tables. | 72 | * Handler Tables. |
69 | */ | 73 | */ |
@@ -94,32 +98,37 @@ static fn_handler_fn *fn_handler[] = { FN_HANDLERS }; | |||
94 | * Variables exported for vt_ioctl.c | 98 | * Variables exported for vt_ioctl.c |
95 | */ | 99 | */ |
96 | 100 | ||
101 | /* maximum values each key_handler can handle */ | ||
102 | const int max_vals[] = { | ||
103 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | ||
104 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | ||
105 | 255, NR_LOCK - 1, 255, NR_BRL - 1 | ||
106 | }; | ||
107 | |||
108 | const int NR_TYPES = ARRAY_SIZE(max_vals); | ||
109 | |||
110 | struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | ||
111 | EXPORT_SYMBOL_GPL(kbd_table); | ||
112 | static struct kbd_struct *kbd = kbd_table; | ||
113 | |||
97 | struct vt_spawn_console vt_spawn_con = { | 114 | struct vt_spawn_console vt_spawn_con = { |
98 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), | 115 | .lock = __SPIN_LOCK_UNLOCKED(vt_spawn_con.lock), |
99 | .pid = NULL, | 116 | .pid = NULL, |
100 | .sig = 0, | 117 | .sig = 0, |
101 | }; | 118 | }; |
102 | 119 | ||
103 | |||
104 | /* | 120 | /* |
105 | * Internal Data. | 121 | * Variables exported for vt.c |
106 | */ | 122 | */ |
107 | 123 | ||
108 | static struct kbd_struct kbd_table[MAX_NR_CONSOLES]; | 124 | int shift_state = 0; |
109 | static struct kbd_struct *kbd = kbd_table; | ||
110 | 125 | ||
111 | /* maximum values each key_handler can handle */ | 126 | /* |
112 | static const int max_vals[] = { | 127 | * Internal Data. |
113 | 255, ARRAY_SIZE(func_table) - 1, ARRAY_SIZE(fn_handler) - 1, NR_PAD - 1, | 128 | */ |
114 | NR_DEAD - 1, 255, 3, NR_SHIFT - 1, 255, NR_ASCII - 1, NR_LOCK - 1, | ||
115 | 255, NR_LOCK - 1, 255, NR_BRL - 1 | ||
116 | }; | ||
117 | |||
118 | static const int NR_TYPES = ARRAY_SIZE(max_vals); | ||
119 | 129 | ||
120 | static struct input_handler kbd_handler; | 130 | static struct input_handler kbd_handler; |
121 | static DEFINE_SPINLOCK(kbd_event_lock); | 131 | static DEFINE_SPINLOCK(kbd_event_lock); |
122 | static DEFINE_SPINLOCK(led_lock); | ||
123 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ | 132 | static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */ |
124 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ | 133 | static unsigned char shift_down[NR_SHIFT]; /* shift state counters.. */ |
125 | static bool dead_key_next; | 134 | static bool dead_key_next; |
@@ -127,8 +136,6 @@ static int npadch = -1; /* -1 or number assembled on pad */ | |||
127 | static unsigned int diacr; | 136 | static unsigned int diacr; |
128 | static char rep; /* flag telling character repeat */ | 137 | static char rep; /* flag telling character repeat */ |
129 | 138 | ||
130 | static int shift_state = 0; | ||
131 | |||
132 | static unsigned char ledstate = 0xff; /* undefined */ | 139 | static unsigned char ledstate = 0xff; /* undefined */ |
133 | static unsigned char ledioctl; | 140 | static unsigned char ledioctl; |
134 | 141 | ||
@@ -179,7 +186,7 @@ static int getkeycode_helper(struct input_handle *handle, void *data) | |||
179 | return d->error == 0; /* stop as soon as we successfully get one */ | 186 | return d->error == 0; /* stop as soon as we successfully get one */ |
180 | } | 187 | } |
181 | 188 | ||
182 | static int getkeycode(unsigned int scancode) | 189 | int getkeycode(unsigned int scancode) |
183 | { | 190 | { |
184 | struct getset_keycode_data d = { | 191 | struct getset_keycode_data d = { |
185 | .ke = { | 192 | .ke = { |
@@ -206,7 +213,7 @@ static int setkeycode_helper(struct input_handle *handle, void *data) | |||
206 | return d->error == 0; /* stop as soon as we successfully set one */ | 213 | return d->error == 0; /* stop as soon as we successfully set one */ |
207 | } | 214 | } |
208 | 215 | ||
209 | static int setkeycode(unsigned int scancode, unsigned int keycode) | 216 | int setkeycode(unsigned int scancode, unsigned int keycode) |
210 | { | 217 | { |
211 | struct getset_keycode_data d = { | 218 | struct getset_keycode_data d = { |
212 | .ke = { | 219 | .ke = { |
@@ -311,7 +318,7 @@ static void put_queue(struct vc_data *vc, int ch) | |||
311 | 318 | ||
312 | if (tty) { | 319 | if (tty) { |
313 | tty_insert_flip_char(tty, ch, 0); | 320 | tty_insert_flip_char(tty, ch, 0); |
314 | tty_schedule_flip(tty); | 321 | con_schedule_flip(tty); |
315 | } | 322 | } |
316 | } | 323 | } |
317 | 324 | ||
@@ -326,7 +333,7 @@ static void puts_queue(struct vc_data *vc, char *cp) | |||
326 | tty_insert_flip_char(tty, *cp, 0); | 333 | tty_insert_flip_char(tty, *cp, 0); |
327 | cp++; | 334 | cp++; |
328 | } | 335 | } |
329 | tty_schedule_flip(tty); | 336 | con_schedule_flip(tty); |
330 | } | 337 | } |
331 | 338 | ||
332 | static void applkey(struct vc_data *vc, int key, char mode) | 339 | static void applkey(struct vc_data *vc, int key, char mode) |
@@ -374,11 +381,9 @@ static void to_utf8(struct vc_data *vc, uint c) | |||
374 | /* | 381 | /* |
375 | * Called after returning from RAW mode or when changing consoles - recompute | 382 | * Called after returning from RAW mode or when changing consoles - recompute |
376 | * shift_down[] and shift_state from key_down[] maybe called when keymap is | 383 | * shift_down[] and shift_state from key_down[] maybe called when keymap is |
377 | * undefined, so that shiftkey release is seen. The caller must hold the | 384 | * undefined, so that shiftkey release is seen |
378 | * kbd_event_lock. | ||
379 | */ | 385 | */ |
380 | 386 | void compute_shiftstate(void) | |
381 | static void do_compute_shiftstate(void) | ||
382 | { | 387 | { |
383 | unsigned int i, j, k, sym, val; | 388 | unsigned int i, j, k, sym, val; |
384 | 389 | ||
@@ -411,15 +416,6 @@ static void do_compute_shiftstate(void) | |||
411 | } | 416 | } |
412 | } | 417 | } |
413 | 418 | ||
414 | /* We still have to export this method to vt.c */ | ||
415 | void compute_shiftstate(void) | ||
416 | { | ||
417 | unsigned long flags; | ||
418 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
419 | do_compute_shiftstate(); | ||
420 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
421 | } | ||
422 | |||
423 | /* | 419 | /* |
424 | * We have a combining character DIACR here, followed by the character CH. | 420 | * We have a combining character DIACR here, followed by the character CH. |
425 | * If the combination occurs in the table, return the corresponding value. | 421 | * If the combination occurs in the table, return the corresponding value. |
@@ -587,7 +583,7 @@ static void fn_send_intr(struct vc_data *vc) | |||
587 | if (!tty) | 583 | if (!tty) |
588 | return; | 584 | return; |
589 | tty_insert_flip_char(tty, 0, TTY_BREAK); | 585 | tty_insert_flip_char(tty, 0, TTY_BREAK); |
590 | tty_schedule_flip(tty); | 586 | con_schedule_flip(tty); |
591 | } | 587 | } |
592 | 588 | ||
593 | static void fn_scroll_forw(struct vc_data *vc) | 589 | static void fn_scroll_forw(struct vc_data *vc) |
@@ -639,7 +635,7 @@ static void fn_SAK(struct vc_data *vc) | |||
639 | 635 | ||
640 | static void fn_null(struct vc_data *vc) | 636 | static void fn_null(struct vc_data *vc) |
641 | { | 637 | { |
642 | do_compute_shiftstate(); | 638 | compute_shiftstate(); |
643 | } | 639 | } |
644 | 640 | ||
645 | /* | 641 | /* |
@@ -985,15 +981,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag) | |||
985 | * or (ii) whatever pattern of lights people want to show using KDSETLED, | 981 | * or (ii) whatever pattern of lights people want to show using KDSETLED, |
986 | * or (iii) specified bits of specified words in kernel memory. | 982 | * or (iii) specified bits of specified words in kernel memory. |
987 | */ | 983 | */ |
988 | static unsigned char getledstate(void) | 984 | unsigned char getledstate(void) |
989 | { | 985 | { |
990 | return ledstate; | 986 | return ledstate; |
991 | } | 987 | } |
992 | 988 | ||
993 | void setledstate(struct kbd_struct *kbd, unsigned int led) | 989 | void setledstate(struct kbd_struct *kbd, unsigned int led) |
994 | { | 990 | { |
995 | unsigned long flags; | ||
996 | spin_lock_irqsave(&led_lock, flags); | ||
997 | if (!(led & ~7)) { | 991 | if (!(led & ~7)) { |
998 | ledioctl = led; | 992 | ledioctl = led; |
999 | kbd->ledmode = LED_SHOW_IOCTL; | 993 | kbd->ledmode = LED_SHOW_IOCTL; |
@@ -1001,7 +995,6 @@ void setledstate(struct kbd_struct *kbd, unsigned int led) | |||
1001 | kbd->ledmode = LED_SHOW_FLAGS; | 995 | kbd->ledmode = LED_SHOW_FLAGS; |
1002 | 996 | ||
1003 | set_leds(); | 997 | set_leds(); |
1004 | spin_unlock_irqrestore(&led_lock, flags); | ||
1005 | } | 998 | } |
1006 | 999 | ||
1007 | static inline unsigned char getleds(void) | 1000 | static inline unsigned char getleds(void) |
@@ -1041,96 +1034,16 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data) | |||
1041 | return 0; | 1034 | return 0; |
1042 | } | 1035 | } |
1043 | 1036 | ||
1044 | /** | ||
1045 | * vt_get_leds - helper for braille console | ||
1046 | * @console: console to read | ||
1047 | * @flag: flag we want to check | ||
1048 | * | ||
1049 | * Check the status of a keyboard led flag and report it back | ||
1050 | */ | ||
1051 | int vt_get_leds(int console, int flag) | ||
1052 | { | ||
1053 | struct kbd_struct * kbd = kbd_table + console; | ||
1054 | int ret; | ||
1055 | unsigned long flags; | ||
1056 | |||
1057 | spin_lock_irqsave(&led_lock, flags); | ||
1058 | ret = vc_kbd_led(kbd, flag); | ||
1059 | spin_unlock_irqrestore(&led_lock, flags); | ||
1060 | |||
1061 | return ret; | ||
1062 | } | ||
1063 | EXPORT_SYMBOL_GPL(vt_get_leds); | ||
1064 | |||
1065 | /** | ||
1066 | * vt_set_led_state - set LED state of a console | ||
1067 | * @console: console to set | ||
1068 | * @leds: LED bits | ||
1069 | * | ||
1070 | * Set the LEDs on a console. This is a wrapper for the VT layer | ||
1071 | * so that we can keep kbd knowledge internal | ||
1072 | */ | ||
1073 | void vt_set_led_state(int console, int leds) | ||
1074 | { | ||
1075 | struct kbd_struct * kbd = kbd_table + console; | ||
1076 | setledstate(kbd, leds); | ||
1077 | } | ||
1078 | |||
1079 | /** | ||
1080 | * vt_kbd_con_start - Keyboard side of console start | ||
1081 | * @console: console | ||
1082 | * | ||
1083 | * Handle console start. This is a wrapper for the VT layer | ||
1084 | * so that we can keep kbd knowledge internal | ||
1085 | * | ||
1086 | * FIXME: We eventually need to hold the kbd lock here to protect | ||
1087 | * the LED updating. We can't do it yet because fn_hold calls stop_tty | ||
1088 | * and start_tty under the kbd_event_lock, while normal tty paths | ||
1089 | * don't hold the lock. We probably need to split out an LED lock | ||
1090 | * but not during an -rc release! | ||
1091 | */ | ||
1092 | void vt_kbd_con_start(int console) | ||
1093 | { | ||
1094 | struct kbd_struct * kbd = kbd_table + console; | ||
1095 | unsigned long flags; | ||
1096 | spin_lock_irqsave(&led_lock, flags); | ||
1097 | clr_vc_kbd_led(kbd, VC_SCROLLOCK); | ||
1098 | set_leds(); | ||
1099 | spin_unlock_irqrestore(&led_lock, flags); | ||
1100 | } | ||
1101 | |||
1102 | /** | ||
1103 | * vt_kbd_con_stop - Keyboard side of console stop | ||
1104 | * @console: console | ||
1105 | * | ||
1106 | * Handle console stop. This is a wrapper for the VT layer | ||
1107 | * so that we can keep kbd knowledge internal | ||
1108 | */ | ||
1109 | void vt_kbd_con_stop(int console) | ||
1110 | { | ||
1111 | struct kbd_struct * kbd = kbd_table + console; | ||
1112 | unsigned long flags; | ||
1113 | spin_lock_irqsave(&led_lock, flags); | ||
1114 | set_vc_kbd_led(kbd, VC_SCROLLOCK); | ||
1115 | set_leds(); | ||
1116 | spin_unlock_irqrestore(&led_lock, flags); | ||
1117 | } | ||
1118 | |||
1119 | /* | 1037 | /* |
1120 | * This is the tasklet that updates LED state on all keyboards | 1038 | * This is the tasklet that updates LED state on all keyboards |
1121 | * attached to the box. The reason we use tasklet is that we | 1039 | * attached to the box. The reason we use tasklet is that we |
1122 | * need to handle the scenario when keyboard handler is not | 1040 | * need to handle the scenario when keyboard handler is not |
1123 | * registered yet but we already getting updates from the VT to | 1041 | * registered yet but we already getting updates form VT to |
1124 | * update led state. | 1042 | * update led state. |
1125 | */ | 1043 | */ |
1126 | static void kbd_bh(unsigned long dummy) | 1044 | static void kbd_bh(unsigned long dummy) |
1127 | { | 1045 | { |
1128 | unsigned char leds; | 1046 | unsigned char leds = getleds(); |
1129 | unsigned long flags; | ||
1130 | |||
1131 | spin_lock_irqsave(&led_lock, flags); | ||
1132 | leds = getleds(); | ||
1133 | spin_unlock_irqrestore(&led_lock, flags); | ||
1134 | 1047 | ||
1135 | if (leds != ledstate) { | 1048 | if (leds != ledstate) { |
1136 | input_handler_for_each_handle(&kbd_handler, &leds, | 1049 | input_handler_for_each_handle(&kbd_handler, &leds, |
@@ -1340,7 +1253,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) | |||
1340 | if (rc == NOTIFY_STOP || !key_map) { | 1253 | if (rc == NOTIFY_STOP || !key_map) { |
1341 | atomic_notifier_call_chain(&keyboard_notifier_list, | 1254 | atomic_notifier_call_chain(&keyboard_notifier_list, |
1342 | KBD_UNBOUND_KEYCODE, ¶m); | 1255 | KBD_UNBOUND_KEYCODE, ¶m); |
1343 | do_compute_shiftstate(); | 1256 | compute_shiftstate(); |
1344 | kbd->slockstate = 0; | 1257 | kbd->slockstate = 0; |
1345 | return; | 1258 | return; |
1346 | } | 1259 | } |
@@ -1490,14 +1403,14 @@ static void kbd_start(struct input_handle *handle) | |||
1490 | 1403 | ||
1491 | static const struct input_device_id kbd_ids[] = { | 1404 | static const struct input_device_id kbd_ids[] = { |
1492 | { | 1405 | { |
1493 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | 1406 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
1494 | .evbit = { BIT_MASK(EV_KEY) }, | 1407 | .evbit = { BIT_MASK(EV_KEY) }, |
1495 | }, | 1408 | }, |
1496 | 1409 | ||
1497 | { | 1410 | { |
1498 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, | 1411 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT, |
1499 | .evbit = { BIT_MASK(EV_SND) }, | 1412 | .evbit = { BIT_MASK(EV_SND) }, |
1500 | }, | 1413 | }, |
1501 | 1414 | ||
1502 | { }, /* Terminating entry */ | 1415 | { }, /* Terminating entry */ |
1503 | }; | 1416 | }; |
@@ -1519,9 +1432,9 @@ int __init kbd_init(void) | |||
1519 | int i; | 1432 | int i; |
1520 | int error; | 1433 | int error; |
1521 | 1434 | ||
1522 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 1435 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
1523 | kbd_table[i].ledflagstate = kbd_defleds(); | 1436 | kbd_table[i].ledflagstate = KBD_DEFLEDS; |
1524 | kbd_table[i].default_ledflagstate = kbd_defleds(); | 1437 | kbd_table[i].default_ledflagstate = KBD_DEFLEDS; |
1525 | kbd_table[i].ledmode = LED_SHOW_FLAGS; | 1438 | kbd_table[i].ledmode = LED_SHOW_FLAGS; |
1526 | kbd_table[i].lockstate = KBD_DEFLOCK; | 1439 | kbd_table[i].lockstate = KBD_DEFLOCK; |
1527 | kbd_table[i].slockstate = 0; | 1440 | kbd_table[i].slockstate = 0; |
@@ -1538,660 +1451,3 @@ int __init kbd_init(void) | |||
1538 | 1451 | ||
1539 | return 0; | 1452 | return 0; |
1540 | } | 1453 | } |
1541 | |||
1542 | /* Ioctl support code */ | ||
1543 | |||
1544 | /** | ||
1545 | * vt_do_diacrit - diacritical table updates | ||
1546 | * @cmd: ioctl request | ||
1547 | * @up: pointer to user data for ioctl | ||
1548 | * @perm: permissions check computed by caller | ||
1549 | * | ||
1550 | * Update the diacritical tables atomically and safely. Lock them | ||
1551 | * against simultaneous keypresses | ||
1552 | */ | ||
1553 | int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) | ||
1554 | { | ||
1555 | struct kbdiacrs __user *a = up; | ||
1556 | unsigned long flags; | ||
1557 | int asize; | ||
1558 | int ret = 0; | ||
1559 | |||
1560 | switch (cmd) { | ||
1561 | case KDGKBDIACR: | ||
1562 | { | ||
1563 | struct kbdiacr *diacr; | ||
1564 | int i; | ||
1565 | |||
1566 | diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), | ||
1567 | GFP_KERNEL); | ||
1568 | if (diacr == NULL) | ||
1569 | return -ENOMEM; | ||
1570 | |||
1571 | /* Lock the diacriticals table, make a copy and then | ||
1572 | copy it after we unlock */ | ||
1573 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1574 | |||
1575 | asize = accent_table_size; | ||
1576 | for (i = 0; i < asize; i++) { | ||
1577 | diacr[i].diacr = conv_uni_to_8bit( | ||
1578 | accent_table[i].diacr); | ||
1579 | diacr[i].base = conv_uni_to_8bit( | ||
1580 | accent_table[i].base); | ||
1581 | diacr[i].result = conv_uni_to_8bit( | ||
1582 | accent_table[i].result); | ||
1583 | } | ||
1584 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1585 | |||
1586 | if (put_user(asize, &a->kb_cnt)) | ||
1587 | ret = -EFAULT; | ||
1588 | else if (copy_to_user(a->kbdiacr, diacr, | ||
1589 | asize * sizeof(struct kbdiacr))) | ||
1590 | ret = -EFAULT; | ||
1591 | kfree(diacr); | ||
1592 | return ret; | ||
1593 | } | ||
1594 | case KDGKBDIACRUC: | ||
1595 | { | ||
1596 | struct kbdiacrsuc __user *a = up; | ||
1597 | void *buf; | ||
1598 | |||
1599 | buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), | ||
1600 | GFP_KERNEL); | ||
1601 | if (buf == NULL) | ||
1602 | return -ENOMEM; | ||
1603 | |||
1604 | /* Lock the diacriticals table, make a copy and then | ||
1605 | copy it after we unlock */ | ||
1606 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1607 | |||
1608 | asize = accent_table_size; | ||
1609 | memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); | ||
1610 | |||
1611 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1612 | |||
1613 | if (put_user(asize, &a->kb_cnt)) | ||
1614 | ret = -EFAULT; | ||
1615 | else if (copy_to_user(a->kbdiacruc, buf, | ||
1616 | asize*sizeof(struct kbdiacruc))) | ||
1617 | ret = -EFAULT; | ||
1618 | kfree(buf); | ||
1619 | return ret; | ||
1620 | } | ||
1621 | |||
1622 | case KDSKBDIACR: | ||
1623 | { | ||
1624 | struct kbdiacrs __user *a = up; | ||
1625 | struct kbdiacr *diacr = NULL; | ||
1626 | unsigned int ct; | ||
1627 | int i; | ||
1628 | |||
1629 | if (!perm) | ||
1630 | return -EPERM; | ||
1631 | if (get_user(ct, &a->kb_cnt)) | ||
1632 | return -EFAULT; | ||
1633 | if (ct >= MAX_DIACR) | ||
1634 | return -EINVAL; | ||
1635 | |||
1636 | if (ct) { | ||
1637 | diacr = kmalloc(sizeof(struct kbdiacr) * ct, | ||
1638 | GFP_KERNEL); | ||
1639 | if (diacr == NULL) | ||
1640 | return -ENOMEM; | ||
1641 | |||
1642 | if (copy_from_user(diacr, a->kbdiacr, | ||
1643 | sizeof(struct kbdiacr) * ct)) { | ||
1644 | kfree(diacr); | ||
1645 | return -EFAULT; | ||
1646 | } | ||
1647 | } | ||
1648 | |||
1649 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1650 | accent_table_size = ct; | ||
1651 | for (i = 0; i < ct; i++) { | ||
1652 | accent_table[i].diacr = | ||
1653 | conv_8bit_to_uni(diacr[i].diacr); | ||
1654 | accent_table[i].base = | ||
1655 | conv_8bit_to_uni(diacr[i].base); | ||
1656 | accent_table[i].result = | ||
1657 | conv_8bit_to_uni(diacr[i].result); | ||
1658 | } | ||
1659 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1660 | kfree(diacr); | ||
1661 | return 0; | ||
1662 | } | ||
1663 | |||
1664 | case KDSKBDIACRUC: | ||
1665 | { | ||
1666 | struct kbdiacrsuc __user *a = up; | ||
1667 | unsigned int ct; | ||
1668 | void *buf = NULL; | ||
1669 | |||
1670 | if (!perm) | ||
1671 | return -EPERM; | ||
1672 | |||
1673 | if (get_user(ct, &a->kb_cnt)) | ||
1674 | return -EFAULT; | ||
1675 | |||
1676 | if (ct >= MAX_DIACR) | ||
1677 | return -EINVAL; | ||
1678 | |||
1679 | if (ct) { | ||
1680 | buf = kmalloc(ct * sizeof(struct kbdiacruc), | ||
1681 | GFP_KERNEL); | ||
1682 | if (buf == NULL) | ||
1683 | return -ENOMEM; | ||
1684 | |||
1685 | if (copy_from_user(buf, a->kbdiacruc, | ||
1686 | ct * sizeof(struct kbdiacruc))) { | ||
1687 | kfree(buf); | ||
1688 | return -EFAULT; | ||
1689 | } | ||
1690 | } | ||
1691 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1692 | if (ct) | ||
1693 | memcpy(accent_table, buf, | ||
1694 | ct * sizeof(struct kbdiacruc)); | ||
1695 | accent_table_size = ct; | ||
1696 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1697 | kfree(buf); | ||
1698 | return 0; | ||
1699 | } | ||
1700 | } | ||
1701 | return ret; | ||
1702 | } | ||
1703 | |||
1704 | /** | ||
1705 | * vt_do_kdskbmode - set keyboard mode ioctl | ||
1706 | * @console: the console to use | ||
1707 | * @arg: the requested mode | ||
1708 | * | ||
1709 | * Update the keyboard mode bits while holding the correct locks. | ||
1710 | * Return 0 for success or an error code. | ||
1711 | */ | ||
1712 | int vt_do_kdskbmode(int console, unsigned int arg) | ||
1713 | { | ||
1714 | struct kbd_struct * kbd = kbd_table + console; | ||
1715 | int ret = 0; | ||
1716 | unsigned long flags; | ||
1717 | |||
1718 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1719 | switch(arg) { | ||
1720 | case K_RAW: | ||
1721 | kbd->kbdmode = VC_RAW; | ||
1722 | break; | ||
1723 | case K_MEDIUMRAW: | ||
1724 | kbd->kbdmode = VC_MEDIUMRAW; | ||
1725 | break; | ||
1726 | case K_XLATE: | ||
1727 | kbd->kbdmode = VC_XLATE; | ||
1728 | do_compute_shiftstate(); | ||
1729 | break; | ||
1730 | case K_UNICODE: | ||
1731 | kbd->kbdmode = VC_UNICODE; | ||
1732 | do_compute_shiftstate(); | ||
1733 | break; | ||
1734 | case K_OFF: | ||
1735 | kbd->kbdmode = VC_OFF; | ||
1736 | break; | ||
1737 | default: | ||
1738 | ret = -EINVAL; | ||
1739 | } | ||
1740 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1741 | return ret; | ||
1742 | } | ||
1743 | |||
1744 | /** | ||
1745 | * vt_do_kdskbmeta - set keyboard meta state | ||
1746 | * @console: the console to use | ||
1747 | * @arg: the requested meta state | ||
1748 | * | ||
1749 | * Update the keyboard meta bits while holding the correct locks. | ||
1750 | * Return 0 for success or an error code. | ||
1751 | */ | ||
1752 | int vt_do_kdskbmeta(int console, unsigned int arg) | ||
1753 | { | ||
1754 | struct kbd_struct * kbd = kbd_table + console; | ||
1755 | int ret = 0; | ||
1756 | unsigned long flags; | ||
1757 | |||
1758 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1759 | switch(arg) { | ||
1760 | case K_METABIT: | ||
1761 | clr_vc_kbd_mode(kbd, VC_META); | ||
1762 | break; | ||
1763 | case K_ESCPREFIX: | ||
1764 | set_vc_kbd_mode(kbd, VC_META); | ||
1765 | break; | ||
1766 | default: | ||
1767 | ret = -EINVAL; | ||
1768 | } | ||
1769 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1770 | return ret; | ||
1771 | } | ||
1772 | |||
1773 | int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, | ||
1774 | int perm) | ||
1775 | { | ||
1776 | struct kbkeycode tmp; | ||
1777 | int kc = 0; | ||
1778 | |||
1779 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) | ||
1780 | return -EFAULT; | ||
1781 | switch (cmd) { | ||
1782 | case KDGETKEYCODE: | ||
1783 | kc = getkeycode(tmp.scancode); | ||
1784 | if (kc >= 0) | ||
1785 | kc = put_user(kc, &user_kbkc->keycode); | ||
1786 | break; | ||
1787 | case KDSETKEYCODE: | ||
1788 | if (!perm) | ||
1789 | return -EPERM; | ||
1790 | kc = setkeycode(tmp.scancode, tmp.keycode); | ||
1791 | break; | ||
1792 | } | ||
1793 | return kc; | ||
1794 | } | ||
1795 | |||
1796 | #define i (tmp.kb_index) | ||
1797 | #define s (tmp.kb_table) | ||
1798 | #define v (tmp.kb_value) | ||
1799 | |||
1800 | int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, | ||
1801 | int console) | ||
1802 | { | ||
1803 | struct kbd_struct * kbd = kbd_table + console; | ||
1804 | struct kbentry tmp; | ||
1805 | ushort *key_map, *new_map, val, ov; | ||
1806 | unsigned long flags; | ||
1807 | |||
1808 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) | ||
1809 | return -EFAULT; | ||
1810 | |||
1811 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
1812 | perm = 0; | ||
1813 | |||
1814 | switch (cmd) { | ||
1815 | case KDGKBENT: | ||
1816 | /* Ensure another thread doesn't free it under us */ | ||
1817 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1818 | key_map = key_maps[s]; | ||
1819 | if (key_map) { | ||
1820 | val = U(key_map[i]); | ||
1821 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) | ||
1822 | val = K_HOLE; | ||
1823 | } else | ||
1824 | val = (i ? K_HOLE : K_NOSUCHMAP); | ||
1825 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1826 | return put_user(val, &user_kbe->kb_value); | ||
1827 | case KDSKBENT: | ||
1828 | if (!perm) | ||
1829 | return -EPERM; | ||
1830 | if (!i && v == K_NOSUCHMAP) { | ||
1831 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1832 | /* deallocate map */ | ||
1833 | key_map = key_maps[s]; | ||
1834 | if (s && key_map) { | ||
1835 | key_maps[s] = NULL; | ||
1836 | if (key_map[0] == U(K_ALLOCATED)) { | ||
1837 | kfree(key_map); | ||
1838 | keymap_count--; | ||
1839 | } | ||
1840 | } | ||
1841 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1842 | break; | ||
1843 | } | ||
1844 | |||
1845 | if (KTYP(v) < NR_TYPES) { | ||
1846 | if (KVAL(v) > max_vals[KTYP(v)]) | ||
1847 | return -EINVAL; | ||
1848 | } else | ||
1849 | if (kbd->kbdmode != VC_UNICODE) | ||
1850 | return -EINVAL; | ||
1851 | |||
1852 | /* ++Geert: non-PC keyboards may generate keycode zero */ | ||
1853 | #if !defined(__mc68000__) && !defined(__powerpc__) | ||
1854 | /* assignment to entry 0 only tests validity of args */ | ||
1855 | if (!i) | ||
1856 | break; | ||
1857 | #endif | ||
1858 | |||
1859 | new_map = kmalloc(sizeof(plain_map), GFP_KERNEL); | ||
1860 | if (!new_map) | ||
1861 | return -ENOMEM; | ||
1862 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1863 | key_map = key_maps[s]; | ||
1864 | if (key_map == NULL) { | ||
1865 | int j; | ||
1866 | |||
1867 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && | ||
1868 | !capable(CAP_SYS_RESOURCE)) { | ||
1869 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1870 | kfree(new_map); | ||
1871 | return -EPERM; | ||
1872 | } | ||
1873 | key_maps[s] = new_map; | ||
1874 | key_map = new_map; | ||
1875 | key_map[0] = U(K_ALLOCATED); | ||
1876 | for (j = 1; j < NR_KEYS; j++) | ||
1877 | key_map[j] = U(K_HOLE); | ||
1878 | keymap_count++; | ||
1879 | } else | ||
1880 | kfree(new_map); | ||
1881 | |||
1882 | ov = U(key_map[i]); | ||
1883 | if (v == ov) | ||
1884 | goto out; | ||
1885 | /* | ||
1886 | * Attention Key. | ||
1887 | */ | ||
1888 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) { | ||
1889 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1890 | return -EPERM; | ||
1891 | } | ||
1892 | key_map[i] = U(v); | ||
1893 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) | ||
1894 | do_compute_shiftstate(); | ||
1895 | out: | ||
1896 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1897 | break; | ||
1898 | } | ||
1899 | return 0; | ||
1900 | } | ||
1901 | #undef i | ||
1902 | #undef s | ||
1903 | #undef v | ||
1904 | |||
1905 | /* FIXME: This one needs untangling and locking */ | ||
1906 | int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) | ||
1907 | { | ||
1908 | struct kbsentry *kbs; | ||
1909 | char *p; | ||
1910 | u_char *q; | ||
1911 | u_char __user *up; | ||
1912 | int sz; | ||
1913 | int delta; | ||
1914 | char *first_free, *fj, *fnw; | ||
1915 | int i, j, k; | ||
1916 | int ret; | ||
1917 | |||
1918 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
1919 | perm = 0; | ||
1920 | |||
1921 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); | ||
1922 | if (!kbs) { | ||
1923 | ret = -ENOMEM; | ||
1924 | goto reterr; | ||
1925 | } | ||
1926 | |||
1927 | /* we mostly copy too much here (512bytes), but who cares ;) */ | ||
1928 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { | ||
1929 | ret = -EFAULT; | ||
1930 | goto reterr; | ||
1931 | } | ||
1932 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; | ||
1933 | i = kbs->kb_func; | ||
1934 | |||
1935 | switch (cmd) { | ||
1936 | case KDGKBSENT: | ||
1937 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been | ||
1938 | a struct member */ | ||
1939 | up = user_kdgkb->kb_string; | ||
1940 | p = func_table[i]; | ||
1941 | if(p) | ||
1942 | for ( ; *p && sz; p++, sz--) | ||
1943 | if (put_user(*p, up++)) { | ||
1944 | ret = -EFAULT; | ||
1945 | goto reterr; | ||
1946 | } | ||
1947 | if (put_user('\0', up)) { | ||
1948 | ret = -EFAULT; | ||
1949 | goto reterr; | ||
1950 | } | ||
1951 | kfree(kbs); | ||
1952 | return ((p && *p) ? -EOVERFLOW : 0); | ||
1953 | case KDSKBSENT: | ||
1954 | if (!perm) { | ||
1955 | ret = -EPERM; | ||
1956 | goto reterr; | ||
1957 | } | ||
1958 | |||
1959 | q = func_table[i]; | ||
1960 | first_free = funcbufptr + (funcbufsize - funcbufleft); | ||
1961 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) | ||
1962 | ; | ||
1963 | if (j < MAX_NR_FUNC) | ||
1964 | fj = func_table[j]; | ||
1965 | else | ||
1966 | fj = first_free; | ||
1967 | |||
1968 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); | ||
1969 | if (delta <= funcbufleft) { /* it fits in current buf */ | ||
1970 | if (j < MAX_NR_FUNC) { | ||
1971 | memmove(fj + delta, fj, first_free - fj); | ||
1972 | for (k = j; k < MAX_NR_FUNC; k++) | ||
1973 | if (func_table[k]) | ||
1974 | func_table[k] += delta; | ||
1975 | } | ||
1976 | if (!q) | ||
1977 | func_table[i] = fj; | ||
1978 | funcbufleft -= delta; | ||
1979 | } else { /* allocate a larger buffer */ | ||
1980 | sz = 256; | ||
1981 | while (sz < funcbufsize - funcbufleft + delta) | ||
1982 | sz <<= 1; | ||
1983 | fnw = kmalloc(sz, GFP_KERNEL); | ||
1984 | if(!fnw) { | ||
1985 | ret = -ENOMEM; | ||
1986 | goto reterr; | ||
1987 | } | ||
1988 | |||
1989 | if (!q) | ||
1990 | func_table[i] = fj; | ||
1991 | if (fj > funcbufptr) | ||
1992 | memmove(fnw, funcbufptr, fj - funcbufptr); | ||
1993 | for (k = 0; k < j; k++) | ||
1994 | if (func_table[k]) | ||
1995 | func_table[k] = fnw + (func_table[k] - funcbufptr); | ||
1996 | |||
1997 | if (first_free > fj) { | ||
1998 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); | ||
1999 | for (k = j; k < MAX_NR_FUNC; k++) | ||
2000 | if (func_table[k]) | ||
2001 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; | ||
2002 | } | ||
2003 | if (funcbufptr != func_buf) | ||
2004 | kfree(funcbufptr); | ||
2005 | funcbufptr = fnw; | ||
2006 | funcbufleft = funcbufleft - delta + sz - funcbufsize; | ||
2007 | funcbufsize = sz; | ||
2008 | } | ||
2009 | strcpy(func_table[i], kbs->kb_string); | ||
2010 | break; | ||
2011 | } | ||
2012 | ret = 0; | ||
2013 | reterr: | ||
2014 | kfree(kbs); | ||
2015 | return ret; | ||
2016 | } | ||
2017 | |||
2018 | int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm) | ||
2019 | { | ||
2020 | struct kbd_struct * kbd = kbd_table + console; | ||
2021 | unsigned long flags; | ||
2022 | unsigned char ucval; | ||
2023 | |||
2024 | switch(cmd) { | ||
2025 | /* the ioctls below read/set the flags usually shown in the leds */ | ||
2026 | /* don't use them - they will go away without warning */ | ||
2027 | case KDGKBLED: | ||
2028 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2029 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); | ||
2030 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2031 | return put_user(ucval, (char __user *)arg); | ||
2032 | |||
2033 | case KDSKBLED: | ||
2034 | if (!perm) | ||
2035 | return -EPERM; | ||
2036 | if (arg & ~0x77) | ||
2037 | return -EINVAL; | ||
2038 | spin_lock_irqsave(&led_lock, flags); | ||
2039 | kbd->ledflagstate = (arg & 7); | ||
2040 | kbd->default_ledflagstate = ((arg >> 4) & 7); | ||
2041 | set_leds(); | ||
2042 | spin_unlock_irqrestore(&led_lock, flags); | ||
2043 | return 0; | ||
2044 | |||
2045 | /* the ioctls below only set the lights, not the functions */ | ||
2046 | /* for those, see KDGKBLED and KDSKBLED above */ | ||
2047 | case KDGETLED: | ||
2048 | ucval = getledstate(); | ||
2049 | return put_user(ucval, (char __user *)arg); | ||
2050 | |||
2051 | case KDSETLED: | ||
2052 | if (!perm) | ||
2053 | return -EPERM; | ||
2054 | setledstate(kbd, arg); | ||
2055 | return 0; | ||
2056 | } | ||
2057 | return -ENOIOCTLCMD; | ||
2058 | } | ||
2059 | |||
2060 | int vt_do_kdgkbmode(int console) | ||
2061 | { | ||
2062 | struct kbd_struct * kbd = kbd_table + console; | ||
2063 | /* This is a spot read so needs no locking */ | ||
2064 | switch (kbd->kbdmode) { | ||
2065 | case VC_RAW: | ||
2066 | return K_RAW; | ||
2067 | case VC_MEDIUMRAW: | ||
2068 | return K_MEDIUMRAW; | ||
2069 | case VC_UNICODE: | ||
2070 | return K_UNICODE; | ||
2071 | case VC_OFF: | ||
2072 | return K_OFF; | ||
2073 | default: | ||
2074 | return K_XLATE; | ||
2075 | } | ||
2076 | } | ||
2077 | |||
2078 | /** | ||
2079 | * vt_do_kdgkbmeta - report meta status | ||
2080 | * @console: console to report | ||
2081 | * | ||
2082 | * Report the meta flag status of this console | ||
2083 | */ | ||
2084 | int vt_do_kdgkbmeta(int console) | ||
2085 | { | ||
2086 | struct kbd_struct * kbd = kbd_table + console; | ||
2087 | /* Again a spot read so no locking */ | ||
2088 | return vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT; | ||
2089 | } | ||
2090 | |||
2091 | /** | ||
2092 | * vt_reset_unicode - reset the unicode status | ||
2093 | * @console: console being reset | ||
2094 | * | ||
2095 | * Restore the unicode console state to its default | ||
2096 | */ | ||
2097 | void vt_reset_unicode(int console) | ||
2098 | { | ||
2099 | unsigned long flags; | ||
2100 | |||
2101 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2102 | kbd_table[console].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; | ||
2103 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2104 | } | ||
2105 | |||
2106 | /** | ||
2107 | * vt_get_shiftstate - shift bit state | ||
2108 | * | ||
2109 | * Report the shift bits from the keyboard state. We have to export | ||
2110 | * this to support some oddities in the vt layer. | ||
2111 | */ | ||
2112 | int vt_get_shift_state(void) | ||
2113 | { | ||
2114 | /* Don't lock as this is a transient report */ | ||
2115 | return shift_state; | ||
2116 | } | ||
2117 | |||
2118 | /** | ||
2119 | * vt_reset_keyboard - reset keyboard state | ||
2120 | * @console: console to reset | ||
2121 | * | ||
2122 | * Reset the keyboard bits for a console as part of a general console | ||
2123 | * reset event | ||
2124 | */ | ||
2125 | void vt_reset_keyboard(int console) | ||
2126 | { | ||
2127 | struct kbd_struct * kbd = kbd_table + console; | ||
2128 | unsigned long flags; | ||
2129 | |||
2130 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2131 | set_vc_kbd_mode(kbd, VC_REPEAT); | ||
2132 | clr_vc_kbd_mode(kbd, VC_CKMODE); | ||
2133 | clr_vc_kbd_mode(kbd, VC_APPLIC); | ||
2134 | clr_vc_kbd_mode(kbd, VC_CRLF); | ||
2135 | kbd->lockstate = 0; | ||
2136 | kbd->slockstate = 0; | ||
2137 | spin_lock(&led_lock); | ||
2138 | kbd->ledmode = LED_SHOW_FLAGS; | ||
2139 | kbd->ledflagstate = kbd->default_ledflagstate; | ||
2140 | spin_unlock(&led_lock); | ||
2141 | /* do not do set_leds here because this causes an endless tasklet loop | ||
2142 | when the keyboard hasn't been initialized yet */ | ||
2143 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2144 | } | ||
2145 | |||
2146 | /** | ||
2147 | * vt_get_kbd_mode_bit - read keyboard status bits | ||
2148 | * @console: console to read from | ||
2149 | * @bit: mode bit to read | ||
2150 | * | ||
2151 | * Report back a vt mode bit. We do this without locking so the | ||
2152 | * caller must be sure that there are no synchronization needs | ||
2153 | */ | ||
2154 | |||
2155 | int vt_get_kbd_mode_bit(int console, int bit) | ||
2156 | { | ||
2157 | struct kbd_struct * kbd = kbd_table + console; | ||
2158 | return vc_kbd_mode(kbd, bit); | ||
2159 | } | ||
2160 | |||
2161 | /** | ||
2162 | * vt_set_kbd_mode_bit - read keyboard status bits | ||
2163 | * @console: console to read from | ||
2164 | * @bit: mode bit to read | ||
2165 | * | ||
2166 | * Set a vt mode bit. We do this without locking so the | ||
2167 | * caller must be sure that there are no synchronization needs | ||
2168 | */ | ||
2169 | |||
2170 | void vt_set_kbd_mode_bit(int console, int bit) | ||
2171 | { | ||
2172 | struct kbd_struct * kbd = kbd_table + console; | ||
2173 | unsigned long flags; | ||
2174 | |||
2175 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2176 | set_vc_kbd_mode(kbd, bit); | ||
2177 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2178 | } | ||
2179 | |||
2180 | /** | ||
2181 | * vt_clr_kbd_mode_bit - read keyboard status bits | ||
2182 | * @console: console to read from | ||
2183 | * @bit: mode bit to read | ||
2184 | * | ||
2185 | * Report back a vt mode bit. We do this without locking so the | ||
2186 | * caller must be sure that there are no synchronization needs | ||
2187 | */ | ||
2188 | |||
2189 | void vt_clr_kbd_mode_bit(int console, int bit) | ||
2190 | { | ||
2191 | struct kbd_struct * kbd = kbd_table + console; | ||
2192 | unsigned long flags; | ||
2193 | |||
2194 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
2195 | clr_vc_kbd_mode(kbd, bit); | ||
2196 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
2197 | } | ||
diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 60b7b692605..fb864e7fcd1 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c | |||
@@ -30,7 +30,6 @@ | |||
30 | 30 | ||
31 | extern void poke_blanked_console(void); | 31 | extern void poke_blanked_console(void); |
32 | 32 | ||
33 | /* FIXME: all this needs locking */ | ||
34 | /* Variables for selection control. */ | 33 | /* Variables for selection control. */ |
35 | /* Use a dynamic buffer, instead of static (Dec 1994) */ | 34 | /* Use a dynamic buffer, instead of static (Dec 1994) */ |
36 | struct vc_data *sel_cons; /* must not be deallocated */ | 35 | struct vc_data *sel_cons; /* must not be deallocated */ |
@@ -62,14 +61,10 @@ sel_pos(int n) | |||
62 | use_unicode); | 61 | use_unicode); |
63 | } | 62 | } |
64 | 63 | ||
65 | /** | 64 | /* remove the current selection highlight, if any, |
66 | * clear_selection - remove current selection | 65 | from the console holding the selection. */ |
67 | * | 66 | void |
68 | * Remove the current selection highlight, if any from the console | 67 | clear_selection(void) { |
69 | * holding the selection. The caller must hold the console lock. | ||
70 | */ | ||
71 | void clear_selection(void) | ||
72 | { | ||
73 | highlight_pointer(-1); /* hide the pointer */ | 68 | highlight_pointer(-1); /* hide the pointer */ |
74 | if (sel_start != -1) { | 69 | if (sel_start != -1) { |
75 | highlight(sel_start, sel_end); | 70 | highlight(sel_start, sel_end); |
@@ -79,7 +74,7 @@ void clear_selection(void) | |||
79 | 74 | ||
80 | /* | 75 | /* |
81 | * User settable table: what characters are to be considered alphabetic? | 76 | * User settable table: what characters are to be considered alphabetic? |
82 | * 256 bits. Locked by the console lock. | 77 | * 256 bits |
83 | */ | 78 | */ |
84 | static u32 inwordLut[8]={ | 79 | static u32 inwordLut[8]={ |
85 | 0x00000000, /* control chars */ | 80 | 0x00000000, /* control chars */ |
@@ -96,20 +91,10 @@ static inline int inword(const u16 c) { | |||
96 | return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); | 91 | return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); |
97 | } | 92 | } |
98 | 93 | ||
99 | /** | 94 | /* set inwordLut contents. Invoked by ioctl(). */ |
100 | * set loadlut - load the LUT table | ||
101 | * @p: user table | ||
102 | * | ||
103 | * Load the LUT table from user space. The caller must hold the console | ||
104 | * lock. Make a temporary copy so a partial update doesn't make a mess. | ||
105 | */ | ||
106 | int sel_loadlut(char __user *p) | 95 | int sel_loadlut(char __user *p) |
107 | { | 96 | { |
108 | u32 tmplut[8]; | 97 | return copy_from_user(inwordLut, (u32 __user *)(p+4), 32) ? -EFAULT : 0; |
109 | if (copy_from_user(tmplut, (u32 __user *)(p+4), 32)) | ||
110 | return -EFAULT; | ||
111 | memcpy(inwordLut, tmplut, 32); | ||
112 | return 0; | ||
113 | } | 98 | } |
114 | 99 | ||
115 | /* does screen address p correspond to character at LH/RH edge of screen? */ | 100 | /* does screen address p correspond to character at LH/RH edge of screen? */ |
@@ -145,16 +130,7 @@ static int store_utf8(u16 c, char *p) | |||
145 | } | 130 | } |
146 | } | 131 | } |
147 | 132 | ||
148 | /** | 133 | /* set the current selection. Invoked by ioctl() or by kernel code. */ |
149 | * set_selection - set the current selection. | ||
150 | * @sel: user selection info | ||
151 | * @tty: the console tty | ||
152 | * | ||
153 | * Invoked by the ioctl handle for the vt layer. | ||
154 | * | ||
155 | * The entire selection process is managed under the console_lock. It's | ||
156 | * a lot under the lock but its hardly a performance path | ||
157 | */ | ||
158 | int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) | 134 | int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) |
159 | { | 135 | { |
160 | struct vc_data *vc = vc_cons[fg_console].d; | 136 | struct vc_data *vc = vc_cons[fg_console].d; |
@@ -162,7 +138,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t | |||
162 | char *bp, *obp; | 138 | char *bp, *obp; |
163 | int i, ps, pe, multiplier; | 139 | int i, ps, pe, multiplier; |
164 | u16 c; | 140 | u16 c; |
165 | int mode; | 141 | struct kbd_struct *kbd = kbd_table + fg_console; |
166 | 142 | ||
167 | poke_blanked_console(); | 143 | poke_blanked_console(); |
168 | 144 | ||
@@ -206,11 +182,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t | |||
206 | clear_selection(); | 182 | clear_selection(); |
207 | sel_cons = vc_cons[fg_console].d; | 183 | sel_cons = vc_cons[fg_console].d; |
208 | } | 184 | } |
209 | mode = vt_do_kdgkbmode(fg_console); | 185 | use_unicode = kbd && kbd->kbdmode == VC_UNICODE; |
210 | if (mode == K_UNICODE) | ||
211 | use_unicode = 1; | ||
212 | else | ||
213 | use_unicode = 0; | ||
214 | 186 | ||
215 | switch (sel_mode) | 187 | switch (sel_mode) |
216 | { | 188 | { |
@@ -329,9 +301,6 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t | |||
329 | /* Insert the contents of the selection buffer into the | 301 | /* Insert the contents of the selection buffer into the |
330 | * queue of the tty associated with the current console. | 302 | * queue of the tty associated with the current console. |
331 | * Invoked by ioctl(). | 303 | * Invoked by ioctl(). |
332 | * | ||
333 | * Locking: called without locks. Calls the ldisc wrongly with | ||
334 | * unsafe methods, | ||
335 | */ | 304 | */ |
336 | int paste_selection(struct tty_struct *tty) | 305 | int paste_selection(struct tty_struct *tty) |
337 | { | 306 | { |
@@ -341,13 +310,20 @@ int paste_selection(struct tty_struct *tty) | |||
341 | struct tty_ldisc *ld; | 310 | struct tty_ldisc *ld; |
342 | DECLARE_WAITQUEUE(wait, current); | 311 | DECLARE_WAITQUEUE(wait, current); |
343 | 312 | ||
313 | /* always called with BTM from vt_ioctl */ | ||
314 | WARN_ON(!tty_locked()); | ||
315 | |||
344 | console_lock(); | 316 | console_lock(); |
345 | poke_blanked_console(); | 317 | poke_blanked_console(); |
346 | console_unlock(); | 318 | console_unlock(); |
347 | 319 | ||
348 | ld = tty_ldisc_ref_wait(tty); | 320 | ld = tty_ldisc_ref(tty); |
321 | if (!ld) { | ||
322 | tty_unlock(); | ||
323 | ld = tty_ldisc_ref_wait(tty); | ||
324 | tty_lock(); | ||
325 | } | ||
349 | 326 | ||
350 | /* FIXME: this is completely unsafe */ | ||
351 | add_wait_queue(&vc->paste_wait, &wait); | 327 | add_wait_queue(&vc->paste_wait, &wait); |
352 | while (sel_buffer && sel_buffer_lth > pasted) { | 328 | while (sel_buffer && sel_buffer_lth > pasted) { |
353 | set_current_state(TASK_INTERRUPTIBLE); | 329 | set_current_state(TASK_INTERRUPTIBLE); |
@@ -357,7 +333,8 @@ int paste_selection(struct tty_struct *tty) | |||
357 | } | 333 | } |
358 | count = sel_buffer_lth - pasted; | 334 | count = sel_buffer_lth - pasted; |
359 | count = min(count, tty->receive_room); | 335 | count = min(count, tty->receive_room); |
360 | ld->ops->receive_buf(tty, sel_buffer + pasted, NULL, count); | 336 | tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, |
337 | NULL, count); | ||
361 | pasted += count; | 338 | pasted += count; |
362 | } | 339 | } |
363 | remove_wait_queue(&vc->paste_wait, &wait); | 340 | remove_wait_queue(&vc->paste_wait, &wait); |
diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index fa7268a93c0..66825c9f516 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/major.h> | 23 | #include <linux/major.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | #include <linux/export.h> | ||
26 | #include <linux/tty.h> | 25 | #include <linux/tty.h> |
27 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
28 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
@@ -608,10 +607,10 @@ vcs_open(struct inode *inode, struct file *filp) | |||
608 | unsigned int currcons = iminor(inode) & 127; | 607 | unsigned int currcons = iminor(inode) & 127; |
609 | int ret = 0; | 608 | int ret = 0; |
610 | 609 | ||
611 | console_lock(); | 610 | tty_lock(); |
612 | if(currcons && !vc_cons_allocated(currcons-1)) | 611 | if(currcons && !vc_cons_allocated(currcons-1)) |
613 | ret = -ENXIO; | 612 | ret = -ENXIO; |
614 | console_unlock(); | 613 | tty_unlock(); |
615 | return ret; | 614 | return ret; |
616 | } | 615 | } |
617 | 616 | ||
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8fd89687d06..b3915b7ad3e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c | |||
@@ -99,6 +99,7 @@ | |||
99 | #include <linux/notifier.h> | 99 | #include <linux/notifier.h> |
100 | #include <linux/device.h> | 100 | #include <linux/device.h> |
101 | #include <linux/io.h> | 101 | #include <linux/io.h> |
102 | #include <asm/system.h> | ||
102 | #include <linux/uaccess.h> | 103 | #include <linux/uaccess.h> |
103 | #include <linux/kdb.h> | 104 | #include <linux/kdb.h> |
104 | #include <linux/ctype.h> | 105 | #include <linux/ctype.h> |
@@ -258,7 +259,7 @@ EXPORT_SYMBOL_GPL(unregister_vt_notifier); | |||
258 | 259 | ||
259 | static void notify_write(struct vc_data *vc, unsigned int unicode) | 260 | static void notify_write(struct vc_data *vc, unsigned int unicode) |
260 | { | 261 | { |
261 | struct vt_notifier_param param = { .vc = vc, .c = unicode }; | 262 | struct vt_notifier_param param = { .vc = vc, unicode = unicode }; |
262 | atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, ¶m); | 263 | atomic_notifier_call_chain(&vt_notifier_list, VT_WRITE, ¶m); |
263 | } | 264 | } |
264 | 265 | ||
@@ -537,27 +538,45 @@ void complement_pos(struct vc_data *vc, int offset) | |||
537 | 538 | ||
538 | static void insert_char(struct vc_data *vc, unsigned int nr) | 539 | static void insert_char(struct vc_data *vc, unsigned int nr) |
539 | { | 540 | { |
540 | unsigned short *p = (unsigned short *) vc->vc_pos; | 541 | unsigned short *p, *q = (unsigned short *)vc->vc_pos; |
541 | 542 | ||
542 | scr_memmovew(p + nr, p, (vc->vc_cols - vc->vc_x) * 2); | 543 | p = q + vc->vc_cols - nr - vc->vc_x; |
543 | scr_memsetw(p, vc->vc_video_erase_char, nr * 2); | 544 | while (--p >= q) |
545 | scr_writew(scr_readw(p), p + nr); | ||
546 | scr_memsetw(q, vc->vc_video_erase_char, nr * 2); | ||
544 | vc->vc_need_wrap = 0; | 547 | vc->vc_need_wrap = 0; |
545 | if (DO_UPDATE(vc)) | 548 | if (DO_UPDATE(vc)) { |
546 | do_update_region(vc, (unsigned long) p, | 549 | unsigned short oldattr = vc->vc_attr; |
547 | vc->vc_cols - vc->vc_x); | 550 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x, vc->vc_y, vc->vc_x + nr, 1, |
551 | vc->vc_cols - vc->vc_x - nr); | ||
552 | vc->vc_attr = vc->vc_video_erase_char >> 8; | ||
553 | while (nr--) | ||
554 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, vc->vc_x + nr); | ||
555 | vc->vc_attr = oldattr; | ||
556 | } | ||
548 | } | 557 | } |
549 | 558 | ||
550 | static void delete_char(struct vc_data *vc, unsigned int nr) | 559 | static void delete_char(struct vc_data *vc, unsigned int nr) |
551 | { | 560 | { |
552 | unsigned short *p = (unsigned short *) vc->vc_pos; | 561 | unsigned int i = vc->vc_x; |
562 | unsigned short *p = (unsigned short *)vc->vc_pos; | ||
553 | 563 | ||
554 | scr_memcpyw(p, p + nr, (vc->vc_cols - vc->vc_x - nr) * 2); | 564 | while (++i <= vc->vc_cols - nr) { |
555 | scr_memsetw(p + vc->vc_cols - vc->vc_x - nr, vc->vc_video_erase_char, | 565 | scr_writew(scr_readw(p+nr), p); |
556 | nr * 2); | 566 | p++; |
567 | } | ||
568 | scr_memsetw(p, vc->vc_video_erase_char, nr * 2); | ||
557 | vc->vc_need_wrap = 0; | 569 | vc->vc_need_wrap = 0; |
558 | if (DO_UPDATE(vc)) | 570 | if (DO_UPDATE(vc)) { |
559 | do_update_region(vc, (unsigned long) p, | 571 | unsigned short oldattr = vc->vc_attr; |
560 | vc->vc_cols - vc->vc_x); | 572 | vc->vc_sw->con_bmove(vc, vc->vc_y, vc->vc_x + nr, vc->vc_y, vc->vc_x, 1, |
573 | vc->vc_cols - vc->vc_x - nr); | ||
574 | vc->vc_attr = vc->vc_video_erase_char >> 8; | ||
575 | while (nr--) | ||
576 | vc->vc_sw->con_putc(vc, vc->vc_video_erase_char, vc->vc_y, | ||
577 | vc->vc_cols - 1 - nr); | ||
578 | vc->vc_attr = oldattr; | ||
579 | } | ||
561 | } | 580 | } |
562 | 581 | ||
563 | static int softcursor_original; | 582 | static int softcursor_original; |
@@ -779,7 +798,6 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ | |||
779 | con_set_default_unimap(vc); | 798 | con_set_default_unimap(vc); |
780 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); | 799 | vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL); |
781 | if (!vc->vc_screenbuf) { | 800 | if (!vc->vc_screenbuf) { |
782 | tty_port_destroy(&vc->port); | ||
783 | kfree(vc); | 801 | kfree(vc); |
784 | vc_cons[currcons].d = NULL; | 802 | vc_cons[currcons].d = NULL; |
785 | return -ENOMEM; | 803 | return -ENOMEM; |
@@ -1000,10 +1018,8 @@ void vc_deallocate(unsigned int currcons) | |||
1000 | put_pid(vc->vt_pid); | 1018 | put_pid(vc->vt_pid); |
1001 | module_put(vc->vc_sw->owner); | 1019 | module_put(vc->vc_sw->owner); |
1002 | kfree(vc->vc_screenbuf); | 1020 | kfree(vc->vc_screenbuf); |
1003 | if (currcons >= MIN_NR_CONSOLES) { | 1021 | if (currcons >= MIN_NR_CONSOLES) |
1004 | tty_port_destroy(&vc->port); | ||
1005 | kfree(vc); | 1022 | kfree(vc); |
1006 | } | ||
1007 | vc_cons[currcons].d = NULL; | 1023 | vc_cons[currcons].d = NULL; |
1008 | } | 1024 | } |
1009 | } | 1025 | } |
@@ -1012,9 +1028,9 @@ void vc_deallocate(unsigned int currcons) | |||
1012 | * VT102 emulator | 1028 | * VT102 emulator |
1013 | */ | 1029 | */ |
1014 | 1030 | ||
1015 | #define set_kbd(vc, x) vt_set_kbd_mode_bit((vc)->vc_num, (x)) | 1031 | #define set_kbd(vc, x) set_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
1016 | #define clr_kbd(vc, x) vt_clr_kbd_mode_bit((vc)->vc_num, (x)) | 1032 | #define clr_kbd(vc, x) clr_vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
1017 | #define is_kbd(vc, x) vt_get_kbd_mode_bit((vc)->vc_num, (x)) | 1033 | #define is_kbd(vc, x) vc_kbd_mode(kbd_table + (vc)->vc_num, (x)) |
1018 | 1034 | ||
1019 | #define decarm VC_REPEAT | 1035 | #define decarm VC_REPEAT |
1020 | #define decckm VC_CKMODE | 1036 | #define decckm VC_CKMODE |
@@ -1157,26 +1173,45 @@ static void csi_J(struct vc_data *vc, int vpar) | |||
1157 | case 0: /* erase from cursor to end of display */ | 1173 | case 0: /* erase from cursor to end of display */ |
1158 | count = (vc->vc_scr_end - vc->vc_pos) >> 1; | 1174 | count = (vc->vc_scr_end - vc->vc_pos) >> 1; |
1159 | start = (unsigned short *)vc->vc_pos; | 1175 | start = (unsigned short *)vc->vc_pos; |
1176 | if (DO_UPDATE(vc)) { | ||
1177 | /* do in two stages */ | ||
1178 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, | ||
1179 | vc->vc_cols - vc->vc_x); | ||
1180 | vc->vc_sw->con_clear(vc, vc->vc_y + 1, 0, | ||
1181 | vc->vc_rows - vc->vc_y - 1, | ||
1182 | vc->vc_cols); | ||
1183 | } | ||
1160 | break; | 1184 | break; |
1161 | case 1: /* erase from start to cursor */ | 1185 | case 1: /* erase from start to cursor */ |
1162 | count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; | 1186 | count = ((vc->vc_pos - vc->vc_origin) >> 1) + 1; |
1163 | start = (unsigned short *)vc->vc_origin; | 1187 | start = (unsigned short *)vc->vc_origin; |
1188 | if (DO_UPDATE(vc)) { | ||
1189 | /* do in two stages */ | ||
1190 | vc->vc_sw->con_clear(vc, 0, 0, vc->vc_y, | ||
1191 | vc->vc_cols); | ||
1192 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | ||
1193 | vc->vc_x + 1); | ||
1194 | } | ||
1164 | break; | 1195 | break; |
1165 | case 3: /* erase scroll-back buffer (and whole display) */ | 1196 | case 3: /* erase scroll-back buffer (and whole display) */ |
1166 | scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, | 1197 | scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, |
1167 | vc->vc_screenbuf_size >> 1); | 1198 | vc->vc_screenbuf_size >> 1); |
1168 | set_origin(vc); | 1199 | set_origin(vc); |
1200 | if (CON_IS_VISIBLE(vc)) | ||
1201 | update_screen(vc); | ||
1169 | /* fall through */ | 1202 | /* fall through */ |
1170 | case 2: /* erase whole display */ | 1203 | case 2: /* erase whole display */ |
1171 | count = vc->vc_cols * vc->vc_rows; | 1204 | count = vc->vc_cols * vc->vc_rows; |
1172 | start = (unsigned short *)vc->vc_origin; | 1205 | start = (unsigned short *)vc->vc_origin; |
1206 | if (DO_UPDATE(vc)) | ||
1207 | vc->vc_sw->con_clear(vc, 0, 0, | ||
1208 | vc->vc_rows, | ||
1209 | vc->vc_cols); | ||
1173 | break; | 1210 | break; |
1174 | default: | 1211 | default: |
1175 | return; | 1212 | return; |
1176 | } | 1213 | } |
1177 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); | 1214 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); |
1178 | if (DO_UPDATE(vc)) | ||
1179 | do_update_region(vc, (unsigned long) start, count); | ||
1180 | vc->vc_need_wrap = 0; | 1215 | vc->vc_need_wrap = 0; |
1181 | } | 1216 | } |
1182 | 1217 | ||
@@ -1189,22 +1224,29 @@ static void csi_K(struct vc_data *vc, int vpar) | |||
1189 | case 0: /* erase from cursor to end of line */ | 1224 | case 0: /* erase from cursor to end of line */ |
1190 | count = vc->vc_cols - vc->vc_x; | 1225 | count = vc->vc_cols - vc->vc_x; |
1191 | start = (unsigned short *)vc->vc_pos; | 1226 | start = (unsigned short *)vc->vc_pos; |
1227 | if (DO_UPDATE(vc)) | ||
1228 | vc->vc_sw->con_clear(vc, vc->vc_y, vc->vc_x, 1, | ||
1229 | vc->vc_cols - vc->vc_x); | ||
1192 | break; | 1230 | break; |
1193 | case 1: /* erase from start of line to cursor */ | 1231 | case 1: /* erase from start of line to cursor */ |
1194 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); | 1232 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); |
1195 | count = vc->vc_x + 1; | 1233 | count = vc->vc_x + 1; |
1234 | if (DO_UPDATE(vc)) | ||
1235 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | ||
1236 | vc->vc_x + 1); | ||
1196 | break; | 1237 | break; |
1197 | case 2: /* erase whole line */ | 1238 | case 2: /* erase whole line */ |
1198 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); | 1239 | start = (unsigned short *)(vc->vc_pos - (vc->vc_x << 1)); |
1199 | count = vc->vc_cols; | 1240 | count = vc->vc_cols; |
1241 | if (DO_UPDATE(vc)) | ||
1242 | vc->vc_sw->con_clear(vc, vc->vc_y, 0, 1, | ||
1243 | vc->vc_cols); | ||
1200 | break; | 1244 | break; |
1201 | default: | 1245 | default: |
1202 | return; | 1246 | return; |
1203 | } | 1247 | } |
1204 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); | 1248 | scr_memsetw(start, vc->vc_video_erase_char, 2 * count); |
1205 | vc->vc_need_wrap = 0; | 1249 | vc->vc_need_wrap = 0; |
1206 | if (DO_UPDATE(vc)) | ||
1207 | do_update_region(vc, (unsigned long) start, count); | ||
1208 | } | 1250 | } |
1209 | 1251 | ||
1210 | static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ | 1252 | static void csi_X(struct vc_data *vc, int vpar) /* erase the following vpar positions */ |
@@ -1339,7 +1381,7 @@ static void respond_string(const char *p, struct tty_struct *tty) | |||
1339 | tty_insert_flip_char(tty, *p, 0); | 1381 | tty_insert_flip_char(tty, *p, 0); |
1340 | p++; | 1382 | p++; |
1341 | } | 1383 | } |
1342 | tty_schedule_flip(tty); | 1384 | con_schedule_flip(tty); |
1343 | } | 1385 | } |
1344 | 1386 | ||
1345 | static void cursor_report(struct vc_data *vc, struct tty_struct *tty) | 1387 | static void cursor_report(struct vc_data *vc, struct tty_struct *tty) |
@@ -1610,7 +1652,16 @@ static void reset_terminal(struct vc_data *vc, int do_clear) | |||
1610 | vc->vc_deccm = global_cursor_default; | 1652 | vc->vc_deccm = global_cursor_default; |
1611 | vc->vc_decim = 0; | 1653 | vc->vc_decim = 0; |
1612 | 1654 | ||
1613 | vt_reset_keyboard(vc->vc_num); | 1655 | set_kbd(vc, decarm); |
1656 | clr_kbd(vc, decckm); | ||
1657 | clr_kbd(vc, kbdapplic); | ||
1658 | clr_kbd(vc, lnm); | ||
1659 | kbd_table[vc->vc_num].lockstate = 0; | ||
1660 | kbd_table[vc->vc_num].slockstate = 0; | ||
1661 | kbd_table[vc->vc_num].ledmode = LED_SHOW_FLAGS; | ||
1662 | kbd_table[vc->vc_num].ledflagstate = kbd_table[vc->vc_num].default_ledflagstate; | ||
1663 | /* do not do set_leds here because this causes an endless tasklet loop | ||
1664 | when the keyboard hasn't been initialized yet */ | ||
1614 | 1665 | ||
1615 | vc->vc_cursor_type = cur_default; | 1666 | vc->vc_cursor_type = cur_default; |
1616 | vc->vc_complement_mask = vc->vc_s_complement_mask; | 1667 | vc->vc_complement_mask = vc->vc_s_complement_mask; |
@@ -1928,7 +1979,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) | |||
1928 | case 'q': /* DECLL - but only 3 leds */ | 1979 | case 'q': /* DECLL - but only 3 leds */ |
1929 | /* map 0,1,2,3 to 0,1,2,4 */ | 1980 | /* map 0,1,2,3 to 0,1,2,4 */ |
1930 | if (vc->vc_par[0] < 4) | 1981 | if (vc->vc_par[0] < 4) |
1931 | vt_set_led_state(vc->vc_num, | 1982 | setledstate(kbd_table + vc->vc_num, |
1932 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); | 1983 | (vc->vc_par[0] < 3) ? vc->vc_par[0] : 4); |
1933 | return; | 1984 | return; |
1934 | case 'r': | 1985 | case 'r': |
@@ -2581,9 +2632,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2581 | console_unlock(); | 2632 | console_unlock(); |
2582 | break; | 2633 | break; |
2583 | case TIOCL_SELLOADLUT: | 2634 | case TIOCL_SELLOADLUT: |
2584 | console_lock(); | ||
2585 | ret = sel_loadlut(p); | 2635 | ret = sel_loadlut(p); |
2586 | console_unlock(); | ||
2587 | break; | 2636 | break; |
2588 | case TIOCL_GETSHIFTSTATE: | 2637 | case TIOCL_GETSHIFTSTATE: |
2589 | 2638 | ||
@@ -2593,19 +2642,15 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2593 | * kernel-internal variable; programs not closely | 2642 | * kernel-internal variable; programs not closely |
2594 | * related to the kernel should not use this. | 2643 | * related to the kernel should not use this. |
2595 | */ | 2644 | */ |
2596 | data = vt_get_shift_state(); | 2645 | data = shift_state; |
2597 | ret = __put_user(data, p); | 2646 | ret = __put_user(data, p); |
2598 | break; | 2647 | break; |
2599 | case TIOCL_GETMOUSEREPORTING: | 2648 | case TIOCL_GETMOUSEREPORTING: |
2600 | console_lock(); /* May be overkill */ | ||
2601 | data = mouse_reporting(); | 2649 | data = mouse_reporting(); |
2602 | console_unlock(); | ||
2603 | ret = __put_user(data, p); | 2650 | ret = __put_user(data, p); |
2604 | break; | 2651 | break; |
2605 | case TIOCL_SETVESABLANK: | 2652 | case TIOCL_SETVESABLANK: |
2606 | console_lock(); | ||
2607 | ret = set_vesa_blanking(p); | 2653 | ret = set_vesa_blanking(p); |
2608 | console_unlock(); | ||
2609 | break; | 2654 | break; |
2610 | case TIOCL_GETKMSGREDIRECT: | 2655 | case TIOCL_GETKMSGREDIRECT: |
2611 | data = vt_get_kmsg_redirect(); | 2656 | data = vt_get_kmsg_redirect(); |
@@ -2622,21 +2667,13 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) | |||
2622 | } | 2667 | } |
2623 | break; | 2668 | break; |
2624 | case TIOCL_GETFGCONSOLE: | 2669 | case TIOCL_GETFGCONSOLE: |
2625 | /* No locking needed as this is a transiently | ||
2626 | correct return anyway if the caller hasn't | ||
2627 | disabled switching */ | ||
2628 | ret = fg_console; | 2670 | ret = fg_console; |
2629 | break; | 2671 | break; |
2630 | case TIOCL_SCROLLCONSOLE: | 2672 | case TIOCL_SCROLLCONSOLE: |
2631 | if (get_user(lines, (s32 __user *)(p+4))) { | 2673 | if (get_user(lines, (s32 __user *)(p+4))) { |
2632 | ret = -EFAULT; | 2674 | ret = -EFAULT; |
2633 | } else { | 2675 | } else { |
2634 | /* Need the console lock here. Note that lots | ||
2635 | of other calls need fixing before the lock | ||
2636 | is actually useful ! */ | ||
2637 | console_lock(); | ||
2638 | scrollfront(vc_cons[fg_console].d, lines); | 2676 | scrollfront(vc_cons[fg_console].d, lines); |
2639 | console_unlock(); | ||
2640 | ret = 0; | 2677 | ret = 0; |
2641 | } | 2678 | } |
2642 | break; | 2679 | break; |
@@ -2716,7 +2753,8 @@ static void con_stop(struct tty_struct *tty) | |||
2716 | console_num = tty->index; | 2753 | console_num = tty->index; |
2717 | if (!vc_cons_allocated(console_num)) | 2754 | if (!vc_cons_allocated(console_num)) |
2718 | return; | 2755 | return; |
2719 | vt_kbd_con_stop(console_num); | 2756 | set_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
2757 | set_leds(); | ||
2720 | } | 2758 | } |
2721 | 2759 | ||
2722 | /* | 2760 | /* |
@@ -2730,7 +2768,8 @@ static void con_start(struct tty_struct *tty) | |||
2730 | console_num = tty->index; | 2768 | console_num = tty->index; |
2731 | if (!vc_cons_allocated(console_num)) | 2769 | if (!vc_cons_allocated(console_num)) |
2732 | return; | 2770 | return; |
2733 | vt_kbd_con_start(console_num); | 2771 | clr_vc_kbd_led(kbd_table + console_num, VC_SCROLLOCK); |
2772 | set_leds(); | ||
2734 | } | 2773 | } |
2735 | 2774 | ||
2736 | static void con_flush_chars(struct tty_struct *tty) | 2775 | static void con_flush_chars(struct tty_struct *tty) |
@@ -2751,52 +2790,41 @@ static void con_flush_chars(struct tty_struct *tty) | |||
2751 | /* | 2790 | /* |
2752 | * Allocate the console screen memory. | 2791 | * Allocate the console screen memory. |
2753 | */ | 2792 | */ |
2754 | static int con_install(struct tty_driver *driver, struct tty_struct *tty) | 2793 | static int con_open(struct tty_struct *tty, struct file *filp) |
2755 | { | 2794 | { |
2756 | unsigned int currcons = tty->index; | 2795 | unsigned int currcons = tty->index; |
2757 | struct vc_data *vc; | 2796 | int ret = 0; |
2758 | int ret; | ||
2759 | 2797 | ||
2760 | console_lock(); | 2798 | console_lock(); |
2761 | ret = vc_allocate(currcons); | 2799 | if (tty->driver_data == NULL) { |
2762 | if (ret) | 2800 | ret = vc_allocate(currcons); |
2763 | goto unlock; | 2801 | if (ret == 0) { |
2764 | 2802 | struct vc_data *vc = vc_cons[currcons].d; | |
2765 | vc = vc_cons[currcons].d; | ||
2766 | |||
2767 | /* Still being freed */ | ||
2768 | if (vc->port.tty) { | ||
2769 | ret = -ERESTARTSYS; | ||
2770 | goto unlock; | ||
2771 | } | ||
2772 | |||
2773 | ret = tty_port_install(&vc->port, driver, tty); | ||
2774 | if (ret) | ||
2775 | goto unlock; | ||
2776 | 2803 | ||
2777 | tty->driver_data = vc; | 2804 | /* Still being freed */ |
2778 | vc->port.tty = tty; | 2805 | if (vc->port.tty) { |
2806 | console_unlock(); | ||
2807 | return -ERESTARTSYS; | ||
2808 | } | ||
2809 | tty->driver_data = vc; | ||
2810 | vc->port.tty = tty; | ||
2779 | 2811 | ||
2780 | if (!tty->winsize.ws_row && !tty->winsize.ws_col) { | 2812 | if (!tty->winsize.ws_row && !tty->winsize.ws_col) { |
2781 | tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; | 2813 | tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; |
2782 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; | 2814 | tty->winsize.ws_col = vc_cons[currcons].d->vc_cols; |
2815 | } | ||
2816 | if (vc->vc_utf) | ||
2817 | tty->termios->c_iflag |= IUTF8; | ||
2818 | else | ||
2819 | tty->termios->c_iflag &= ~IUTF8; | ||
2820 | console_unlock(); | ||
2821 | return ret; | ||
2822 | } | ||
2783 | } | 2823 | } |
2784 | if (vc->vc_utf) | ||
2785 | tty->termios.c_iflag |= IUTF8; | ||
2786 | else | ||
2787 | tty->termios.c_iflag &= ~IUTF8; | ||
2788 | unlock: | ||
2789 | console_unlock(); | 2824 | console_unlock(); |
2790 | return ret; | 2825 | return ret; |
2791 | } | 2826 | } |
2792 | 2827 | ||
2793 | static int con_open(struct tty_struct *tty, struct file *filp) | ||
2794 | { | ||
2795 | /* everything done in install */ | ||
2796 | return 0; | ||
2797 | } | ||
2798 | |||
2799 | |||
2800 | static void con_close(struct tty_struct *tty, struct file *filp) | 2828 | static void con_close(struct tty_struct *tty, struct file *filp) |
2801 | { | 2829 | { |
2802 | /* Nothing to do - we defer to shutdown */ | 2830 | /* Nothing to do - we defer to shutdown */ |
@@ -2809,6 +2837,7 @@ static void con_shutdown(struct tty_struct *tty) | |||
2809 | console_lock(); | 2837 | console_lock(); |
2810 | vc->port.tty = NULL; | 2838 | vc->port.tty = NULL; |
2811 | console_unlock(); | 2839 | console_unlock(); |
2840 | tty_shutdown(tty); | ||
2812 | } | 2841 | } |
2813 | 2842 | ||
2814 | static int default_italic_color = 2; // green (ASCII) | 2843 | static int default_italic_color = 2; // green (ASCII) |
@@ -2901,10 +2930,11 @@ static int __init con_init(void) | |||
2901 | gotoxy(vc, vc->vc_x, vc->vc_y); | 2930 | gotoxy(vc, vc->vc_x, vc->vc_y); |
2902 | csi_J(vc, 0); | 2931 | csi_J(vc, 0); |
2903 | update_screen(vc); | 2932 | update_screen(vc); |
2904 | pr_info("Console: %s %s %dx%d\n", | 2933 | pr_info("Console: %s %s %dx%d", |
2905 | vc->vc_can_do_color ? "colour" : "mono", | 2934 | vc->vc_can_do_color ? "colour" : "mono", |
2906 | display_desc, vc->vc_cols, vc->vc_rows); | 2935 | display_desc, vc->vc_cols, vc->vc_rows); |
2907 | printable = 1; | 2936 | printable = 1; |
2937 | printk("\n"); | ||
2908 | 2938 | ||
2909 | console_unlock(); | 2939 | console_unlock(); |
2910 | 2940 | ||
@@ -2916,7 +2946,6 @@ static int __init con_init(void) | |||
2916 | console_initcall(con_init); | 2946 | console_initcall(con_init); |
2917 | 2947 | ||
2918 | static const struct tty_operations con_ops = { | 2948 | static const struct tty_operations con_ops = { |
2919 | .install = con_install, | ||
2920 | .open = con_open, | 2949 | .open = con_open, |
2921 | .close = con_close, | 2950 | .close = con_close, |
2922 | .write = con_write, | 2951 | .write = con_write, |
@@ -2962,7 +2991,7 @@ int __init vty_init(const struct file_operations *console_fops) | |||
2962 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); | 2991 | console_driver = alloc_tty_driver(MAX_NR_CONSOLES); |
2963 | if (!console_driver) | 2992 | if (!console_driver) |
2964 | panic("Couldn't allocate console driver\n"); | 2993 | panic("Couldn't allocate console driver\n"); |
2965 | 2994 | console_driver->owner = THIS_MODULE; | |
2966 | console_driver->name = "tty"; | 2995 | console_driver->name = "tty"; |
2967 | console_driver->name_base = 1; | 2996 | console_driver->name_base = 1; |
2968 | console_driver->major = TTY_MAJOR; | 2997 | console_driver->major = TTY_MAJOR; |
@@ -3445,19 +3474,6 @@ int con_debug_enter(struct vc_data *vc) | |||
3445 | kdb_set(2, setargs); | 3474 | kdb_set(2, setargs); |
3446 | } | 3475 | } |
3447 | } | 3476 | } |
3448 | if (vc->vc_cols < 999) { | ||
3449 | int colcount; | ||
3450 | char cols[4]; | ||
3451 | const char *setargs[3] = { | ||
3452 | "set", | ||
3453 | "COLUMNS", | ||
3454 | cols, | ||
3455 | }; | ||
3456 | if (kdbgetintenv(setargs[0], &colcount)) { | ||
3457 | snprintf(cols, 4, "%i", vc->vc_cols); | ||
3458 | kdb_set(2, setargs); | ||
3459 | } | ||
3460 | } | ||
3461 | #endif /* CONFIG_KGDB_KDB */ | 3477 | #endif /* CONFIG_KGDB_KDB */ |
3462 | return ret; | 3478 | return ret; |
3463 | } | 3479 | } |
@@ -3875,6 +3891,36 @@ static void set_palette(struct vc_data *vc) | |||
3875 | vc->vc_sw->con_set_palette(vc, color_table); | 3891 | vc->vc_sw->con_set_palette(vc, color_table); |
3876 | } | 3892 | } |
3877 | 3893 | ||
3894 | static int set_get_cmap(unsigned char __user *arg, int set) | ||
3895 | { | ||
3896 | int i, j, k; | ||
3897 | |||
3898 | WARN_CONSOLE_UNLOCKED(); | ||
3899 | |||
3900 | for (i = 0; i < 16; i++) | ||
3901 | if (set) { | ||
3902 | get_user(default_red[i], arg++); | ||
3903 | get_user(default_grn[i], arg++); | ||
3904 | get_user(default_blu[i], arg++); | ||
3905 | } else { | ||
3906 | put_user(default_red[i], arg++); | ||
3907 | put_user(default_grn[i], arg++); | ||
3908 | put_user(default_blu[i], arg++); | ||
3909 | } | ||
3910 | if (set) { | ||
3911 | for (i = 0; i < MAX_NR_CONSOLES; i++) | ||
3912 | if (vc_cons_allocated(i)) { | ||
3913 | for (j = k = 0; j < 16; j++) { | ||
3914 | vc_cons[i].d->vc_palette[k++] = default_red[j]; | ||
3915 | vc_cons[i].d->vc_palette[k++] = default_grn[j]; | ||
3916 | vc_cons[i].d->vc_palette[k++] = default_blu[j]; | ||
3917 | } | ||
3918 | set_palette(vc_cons[i].d); | ||
3919 | } | ||
3920 | } | ||
3921 | return 0; | ||
3922 | } | ||
3923 | |||
3878 | /* | 3924 | /* |
3879 | * Load palette into the DAC registers. arg points to a colour | 3925 | * Load palette into the DAC registers. arg points to a colour |
3880 | * map, 3 bytes per colour, 16 colours, range from 0 to 255. | 3926 | * map, 3 bytes per colour, 16 colours, range from 0 to 255. |
@@ -3882,50 +3928,24 @@ static void set_palette(struct vc_data *vc) | |||
3882 | 3928 | ||
3883 | int con_set_cmap(unsigned char __user *arg) | 3929 | int con_set_cmap(unsigned char __user *arg) |
3884 | { | 3930 | { |
3885 | int i, j, k; | 3931 | int rc; |
3886 | unsigned char colormap[3*16]; | ||
3887 | |||
3888 | if (copy_from_user(colormap, arg, sizeof(colormap))) | ||
3889 | return -EFAULT; | ||
3890 | 3932 | ||
3891 | console_lock(); | 3933 | console_lock(); |
3892 | for (i = k = 0; i < 16; i++) { | 3934 | rc = set_get_cmap (arg,1); |
3893 | default_red[i] = colormap[k++]; | ||
3894 | default_grn[i] = colormap[k++]; | ||
3895 | default_blu[i] = colormap[k++]; | ||
3896 | } | ||
3897 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | ||
3898 | if (!vc_cons_allocated(i)) | ||
3899 | continue; | ||
3900 | for (j = k = 0; j < 16; j++) { | ||
3901 | vc_cons[i].d->vc_palette[k++] = default_red[j]; | ||
3902 | vc_cons[i].d->vc_palette[k++] = default_grn[j]; | ||
3903 | vc_cons[i].d->vc_palette[k++] = default_blu[j]; | ||
3904 | } | ||
3905 | set_palette(vc_cons[i].d); | ||
3906 | } | ||
3907 | console_unlock(); | 3935 | console_unlock(); |
3908 | 3936 | ||
3909 | return 0; | 3937 | return rc; |
3910 | } | 3938 | } |
3911 | 3939 | ||
3912 | int con_get_cmap(unsigned char __user *arg) | 3940 | int con_get_cmap(unsigned char __user *arg) |
3913 | { | 3941 | { |
3914 | int i, k; | 3942 | int rc; |
3915 | unsigned char colormap[3*16]; | ||
3916 | 3943 | ||
3917 | console_lock(); | 3944 | console_lock(); |
3918 | for (i = k = 0; i < 16; i++) { | 3945 | rc = set_get_cmap (arg,0); |
3919 | colormap[k++] = default_red[i]; | ||
3920 | colormap[k++] = default_grn[i]; | ||
3921 | colormap[k++] = default_blu[i]; | ||
3922 | } | ||
3923 | console_unlock(); | 3946 | console_unlock(); |
3924 | 3947 | ||
3925 | if (copy_to_user(arg, colormap, sizeof(colormap))) | 3948 | return rc; |
3926 | return -EFAULT; | ||
3927 | |||
3928 | return 0; | ||
3929 | } | 3949 | } |
3930 | 3950 | ||
3931 | void reset_palette(struct vc_data *vc) | 3951 | void reset_palette(struct vc_data *vc) |
@@ -3960,6 +3980,9 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) | |||
3960 | int rc = -EINVAL; | 3980 | int rc = -EINVAL; |
3961 | int c; | 3981 | int c; |
3962 | 3982 | ||
3983 | if (vc->vc_mode != KD_TEXT) | ||
3984 | return -EINVAL; | ||
3985 | |||
3963 | if (op->data) { | 3986 | if (op->data) { |
3964 | font.data = kmalloc(max_font_size, GFP_KERNEL); | 3987 | font.data = kmalloc(max_font_size, GFP_KERNEL); |
3965 | if (!font.data) | 3988 | if (!font.data) |
@@ -3968,9 +3991,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) | |||
3968 | font.data = NULL; | 3991 | font.data = NULL; |
3969 | 3992 | ||
3970 | console_lock(); | 3993 | console_lock(); |
3971 | if (vc->vc_mode != KD_TEXT) | 3994 | if (vc->vc_sw->con_font_get) |
3972 | rc = -EINVAL; | ||
3973 | else if (vc->vc_sw->con_font_get) | ||
3974 | rc = vc->vc_sw->con_font_get(vc, &font); | 3995 | rc = vc->vc_sw->con_font_get(vc, &font); |
3975 | else | 3996 | else |
3976 | rc = -ENOSYS; | 3997 | rc = -ENOSYS; |
@@ -4052,9 +4073,7 @@ static int con_font_set(struct vc_data *vc, struct console_font_op *op) | |||
4052 | if (IS_ERR(font.data)) | 4073 | if (IS_ERR(font.data)) |
4053 | return PTR_ERR(font.data); | 4074 | return PTR_ERR(font.data); |
4054 | console_lock(); | 4075 | console_lock(); |
4055 | if (vc->vc_mode != KD_TEXT) | 4076 | if (vc->vc_sw->con_font_set) |
4056 | rc = -EINVAL; | ||
4057 | else if (vc->vc_sw->con_font_set) | ||
4058 | rc = vc->vc_sw->con_font_set(vc, &font, op->flags); | 4077 | rc = vc->vc_sw->con_font_set(vc, &font, op->flags); |
4059 | else | 4078 | else |
4060 | rc = -ENOSYS; | 4079 | rc = -ENOSYS; |
@@ -4070,6 +4089,8 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) | |||
4070 | char *s = name; | 4089 | char *s = name; |
4071 | int rc; | 4090 | int rc; |
4072 | 4091 | ||
4092 | if (vc->vc_mode != KD_TEXT) | ||
4093 | return -EINVAL; | ||
4073 | 4094 | ||
4074 | if (!op->data) | 4095 | if (!op->data) |
4075 | s = NULL; | 4096 | s = NULL; |
@@ -4079,10 +4100,6 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) | |||
4079 | name[MAX_FONT_NAME - 1] = 0; | 4100 | name[MAX_FONT_NAME - 1] = 0; |
4080 | 4101 | ||
4081 | console_lock(); | 4102 | console_lock(); |
4082 | if (vc->vc_mode != KD_TEXT) { | ||
4083 | console_unlock(); | ||
4084 | return -EINVAL; | ||
4085 | } | ||
4086 | if (vc->vc_sw->con_font_default) | 4103 | if (vc->vc_sw->con_font_default) |
4087 | rc = vc->vc_sw->con_font_default(vc, &font, s); | 4104 | rc = vc->vc_sw->con_font_default(vc, &font, s); |
4088 | else | 4105 | else |
@@ -4100,11 +4117,11 @@ static int con_font_copy(struct vc_data *vc, struct console_font_op *op) | |||
4100 | int con = op->height; | 4117 | int con = op->height; |
4101 | int rc; | 4118 | int rc; |
4102 | 4119 | ||
4120 | if (vc->vc_mode != KD_TEXT) | ||
4121 | return -EINVAL; | ||
4103 | 4122 | ||
4104 | console_lock(); | 4123 | console_lock(); |
4105 | if (vc->vc_mode != KD_TEXT) | 4124 | if (!vc->vc_sw->con_font_copy) |
4106 | rc = -EINVAL; | ||
4107 | else if (!vc->vc_sw->con_font_copy) | ||
4108 | rc = -ENOSYS; | 4125 | rc = -ENOSYS; |
4109 | else if (con < 0 || !vc_cons_allocated(con)) | 4126 | else if (con < 0 || !vc_cons_allocated(con)) |
4110 | rc = -ENOTTY; | 4127 | rc = -ENOTTY; |
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 98ff1735eaf..5e096f43bce 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/console.h> | 25 | #include <linux/console.h> |
26 | #include <linux/consolemap.h> | 26 | #include <linux/consolemap.h> |
27 | #include <linux/signal.h> | 27 | #include <linux/signal.h> |
28 | #include <linux/suspend.h> | ||
29 | #include <linux/timex.h> | 28 | #include <linux/timex.h> |
30 | 29 | ||
31 | #include <asm/io.h> | 30 | #include <asm/io.h> |
@@ -111,7 +110,16 @@ void vt_event_post(unsigned int event, unsigned int old, unsigned int new) | |||
111 | wake_up_interruptible(&vt_event_waitqueue); | 110 | wake_up_interruptible(&vt_event_waitqueue); |
112 | } | 111 | } |
113 | 112 | ||
114 | static void __vt_event_queue(struct vt_event_wait *vw) | 113 | /** |
114 | * vt_event_wait - wait for an event | ||
115 | * @vw: our event | ||
116 | * | ||
117 | * Waits for an event to occur which completes our vt_event_wait | ||
118 | * structure. On return the structure has wv->done set to 1 for success | ||
119 | * or 0 if some event such as a signal ended the wait. | ||
120 | */ | ||
121 | |||
122 | static void vt_event_wait(struct vt_event_wait *vw) | ||
115 | { | 123 | { |
116 | unsigned long flags; | 124 | unsigned long flags; |
117 | /* Prepare the event */ | 125 | /* Prepare the event */ |
@@ -121,18 +129,8 @@ static void __vt_event_queue(struct vt_event_wait *vw) | |||
121 | spin_lock_irqsave(&vt_event_lock, flags); | 129 | spin_lock_irqsave(&vt_event_lock, flags); |
122 | list_add(&vw->list, &vt_events); | 130 | list_add(&vw->list, &vt_events); |
123 | spin_unlock_irqrestore(&vt_event_lock, flags); | 131 | spin_unlock_irqrestore(&vt_event_lock, flags); |
124 | } | ||
125 | |||
126 | static void __vt_event_wait(struct vt_event_wait *vw) | ||
127 | { | ||
128 | /* Wait for it to pass */ | 132 | /* Wait for it to pass */ |
129 | wait_event_interruptible(vt_event_waitqueue, vw->done); | 133 | wait_event_interruptible_tty(vt_event_waitqueue, vw->done); |
130 | } | ||
131 | |||
132 | static void __vt_event_dequeue(struct vt_event_wait *vw) | ||
133 | { | ||
134 | unsigned long flags; | ||
135 | |||
136 | /* Dequeue it */ | 134 | /* Dequeue it */ |
137 | spin_lock_irqsave(&vt_event_lock, flags); | 135 | spin_lock_irqsave(&vt_event_lock, flags); |
138 | list_del(&vw->list); | 136 | list_del(&vw->list); |
@@ -140,22 +138,6 @@ static void __vt_event_dequeue(struct vt_event_wait *vw) | |||
140 | } | 138 | } |
141 | 139 | ||
142 | /** | 140 | /** |
143 | * vt_event_wait - wait for an event | ||
144 | * @vw: our event | ||
145 | * | ||
146 | * Waits for an event to occur which completes our vt_event_wait | ||
147 | * structure. On return the structure has wv->done set to 1 for success | ||
148 | * or 0 if some event such as a signal ended the wait. | ||
149 | */ | ||
150 | |||
151 | static void vt_event_wait(struct vt_event_wait *vw) | ||
152 | { | ||
153 | __vt_event_queue(vw); | ||
154 | __vt_event_wait(vw); | ||
155 | __vt_event_dequeue(vw); | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * vt_event_wait_ioctl - event ioctl handler | 141 | * vt_event_wait_ioctl - event ioctl handler |
160 | * @arg: argument to ioctl | 142 | * @arg: argument to ioctl |
161 | * | 143 | * |
@@ -195,14 +177,10 @@ int vt_waitactive(int n) | |||
195 | { | 177 | { |
196 | struct vt_event_wait vw; | 178 | struct vt_event_wait vw; |
197 | do { | 179 | do { |
198 | vw.event.event = VT_EVENT_SWITCH; | 180 | if (n == fg_console + 1) |
199 | __vt_event_queue(&vw); | ||
200 | if (n == fg_console + 1) { | ||
201 | __vt_event_dequeue(&vw); | ||
202 | break; | 181 | break; |
203 | } | 182 | vw.event.event = VT_EVENT_SWITCH; |
204 | __vt_event_wait(&vw); | 183 | vt_event_wait(&vw); |
205 | __vt_event_dequeue(&vw); | ||
206 | if (vw.done == 0) | 184 | if (vw.done == 0) |
207 | return -EINTR; | 185 | return -EINTR; |
208 | } while (vw.event.newev != n); | 186 | } while (vw.event.newev != n); |
@@ -217,7 +195,232 @@ int vt_waitactive(int n) | |||
217 | #define GPLAST 0x3df | 195 | #define GPLAST 0x3df |
218 | #define GPNUM (GPLAST - GPFIRST + 1) | 196 | #define GPNUM (GPLAST - GPFIRST + 1) |
219 | 197 | ||
198 | #define i (tmp.kb_index) | ||
199 | #define s (tmp.kb_table) | ||
200 | #define v (tmp.kb_value) | ||
201 | static inline int | ||
202 | do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_struct *kbd) | ||
203 | { | ||
204 | struct kbentry tmp; | ||
205 | ushort *key_map, val, ov; | ||
206 | |||
207 | if (copy_from_user(&tmp, user_kbe, sizeof(struct kbentry))) | ||
208 | return -EFAULT; | ||
209 | |||
210 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
211 | perm = 0; | ||
212 | |||
213 | switch (cmd) { | ||
214 | case KDGKBENT: | ||
215 | key_map = key_maps[s]; | ||
216 | if (key_map) { | ||
217 | val = U(key_map[i]); | ||
218 | if (kbd->kbdmode != VC_UNICODE && KTYP(val) >= NR_TYPES) | ||
219 | val = K_HOLE; | ||
220 | } else | ||
221 | val = (i ? K_HOLE : K_NOSUCHMAP); | ||
222 | return put_user(val, &user_kbe->kb_value); | ||
223 | case KDSKBENT: | ||
224 | if (!perm) | ||
225 | return -EPERM; | ||
226 | if (!i && v == K_NOSUCHMAP) { | ||
227 | /* deallocate map */ | ||
228 | key_map = key_maps[s]; | ||
229 | if (s && key_map) { | ||
230 | key_maps[s] = NULL; | ||
231 | if (key_map[0] == U(K_ALLOCATED)) { | ||
232 | kfree(key_map); | ||
233 | keymap_count--; | ||
234 | } | ||
235 | } | ||
236 | break; | ||
237 | } | ||
238 | |||
239 | if (KTYP(v) < NR_TYPES) { | ||
240 | if (KVAL(v) > max_vals[KTYP(v)]) | ||
241 | return -EINVAL; | ||
242 | } else | ||
243 | if (kbd->kbdmode != VC_UNICODE) | ||
244 | return -EINVAL; | ||
245 | |||
246 | /* ++Geert: non-PC keyboards may generate keycode zero */ | ||
247 | #if !defined(__mc68000__) && !defined(__powerpc__) | ||
248 | /* assignment to entry 0 only tests validity of args */ | ||
249 | if (!i) | ||
250 | break; | ||
251 | #endif | ||
252 | |||
253 | if (!(key_map = key_maps[s])) { | ||
254 | int j; | ||
255 | |||
256 | if (keymap_count >= MAX_NR_OF_USER_KEYMAPS && | ||
257 | !capable(CAP_SYS_RESOURCE)) | ||
258 | return -EPERM; | ||
259 | |||
260 | key_map = kmalloc(sizeof(plain_map), | ||
261 | GFP_KERNEL); | ||
262 | if (!key_map) | ||
263 | return -ENOMEM; | ||
264 | key_maps[s] = key_map; | ||
265 | key_map[0] = U(K_ALLOCATED); | ||
266 | for (j = 1; j < NR_KEYS; j++) | ||
267 | key_map[j] = U(K_HOLE); | ||
268 | keymap_count++; | ||
269 | } | ||
270 | ov = U(key_map[i]); | ||
271 | if (v == ov) | ||
272 | break; /* nothing to do */ | ||
273 | /* | ||
274 | * Attention Key. | ||
275 | */ | ||
276 | if (((ov == K_SAK) || (v == K_SAK)) && !capable(CAP_SYS_ADMIN)) | ||
277 | return -EPERM; | ||
278 | key_map[i] = U(v); | ||
279 | if (!s && (KTYP(ov) == KT_SHIFT || KTYP(v) == KT_SHIFT)) | ||
280 | compute_shiftstate(); | ||
281 | break; | ||
282 | } | ||
283 | return 0; | ||
284 | } | ||
285 | #undef i | ||
286 | #undef s | ||
287 | #undef v | ||
288 | |||
289 | static inline int | ||
290 | do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, int perm) | ||
291 | { | ||
292 | struct kbkeycode tmp; | ||
293 | int kc = 0; | ||
294 | |||
295 | if (copy_from_user(&tmp, user_kbkc, sizeof(struct kbkeycode))) | ||
296 | return -EFAULT; | ||
297 | switch (cmd) { | ||
298 | case KDGETKEYCODE: | ||
299 | kc = getkeycode(tmp.scancode); | ||
300 | if (kc >= 0) | ||
301 | kc = put_user(kc, &user_kbkc->keycode); | ||
302 | break; | ||
303 | case KDSETKEYCODE: | ||
304 | if (!perm) | ||
305 | return -EPERM; | ||
306 | kc = setkeycode(tmp.scancode, tmp.keycode); | ||
307 | break; | ||
308 | } | ||
309 | return kc; | ||
310 | } | ||
311 | |||
312 | static inline int | ||
313 | do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, int perm) | ||
314 | { | ||
315 | struct kbsentry *kbs; | ||
316 | char *p; | ||
317 | u_char *q; | ||
318 | u_char __user *up; | ||
319 | int sz; | ||
320 | int delta; | ||
321 | char *first_free, *fj, *fnw; | ||
322 | int i, j, k; | ||
323 | int ret; | ||
324 | |||
325 | if (!capable(CAP_SYS_TTY_CONFIG)) | ||
326 | perm = 0; | ||
327 | |||
328 | kbs = kmalloc(sizeof(*kbs), GFP_KERNEL); | ||
329 | if (!kbs) { | ||
330 | ret = -ENOMEM; | ||
331 | goto reterr; | ||
332 | } | ||
220 | 333 | ||
334 | /* we mostly copy too much here (512bytes), but who cares ;) */ | ||
335 | if (copy_from_user(kbs, user_kdgkb, sizeof(struct kbsentry))) { | ||
336 | ret = -EFAULT; | ||
337 | goto reterr; | ||
338 | } | ||
339 | kbs->kb_string[sizeof(kbs->kb_string)-1] = '\0'; | ||
340 | i = kbs->kb_func; | ||
341 | |||
342 | switch (cmd) { | ||
343 | case KDGKBSENT: | ||
344 | sz = sizeof(kbs->kb_string) - 1; /* sz should have been | ||
345 | a struct member */ | ||
346 | up = user_kdgkb->kb_string; | ||
347 | p = func_table[i]; | ||
348 | if(p) | ||
349 | for ( ; *p && sz; p++, sz--) | ||
350 | if (put_user(*p, up++)) { | ||
351 | ret = -EFAULT; | ||
352 | goto reterr; | ||
353 | } | ||
354 | if (put_user('\0', up)) { | ||
355 | ret = -EFAULT; | ||
356 | goto reterr; | ||
357 | } | ||
358 | kfree(kbs); | ||
359 | return ((p && *p) ? -EOVERFLOW : 0); | ||
360 | case KDSKBSENT: | ||
361 | if (!perm) { | ||
362 | ret = -EPERM; | ||
363 | goto reterr; | ||
364 | } | ||
365 | |||
366 | q = func_table[i]; | ||
367 | first_free = funcbufptr + (funcbufsize - funcbufleft); | ||
368 | for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) | ||
369 | ; | ||
370 | if (j < MAX_NR_FUNC) | ||
371 | fj = func_table[j]; | ||
372 | else | ||
373 | fj = first_free; | ||
374 | |||
375 | delta = (q ? -strlen(q) : 1) + strlen(kbs->kb_string); | ||
376 | if (delta <= funcbufleft) { /* it fits in current buf */ | ||
377 | if (j < MAX_NR_FUNC) { | ||
378 | memmove(fj + delta, fj, first_free - fj); | ||
379 | for (k = j; k < MAX_NR_FUNC; k++) | ||
380 | if (func_table[k]) | ||
381 | func_table[k] += delta; | ||
382 | } | ||
383 | if (!q) | ||
384 | func_table[i] = fj; | ||
385 | funcbufleft -= delta; | ||
386 | } else { /* allocate a larger buffer */ | ||
387 | sz = 256; | ||
388 | while (sz < funcbufsize - funcbufleft + delta) | ||
389 | sz <<= 1; | ||
390 | fnw = kmalloc(sz, GFP_KERNEL); | ||
391 | if(!fnw) { | ||
392 | ret = -ENOMEM; | ||
393 | goto reterr; | ||
394 | } | ||
395 | |||
396 | if (!q) | ||
397 | func_table[i] = fj; | ||
398 | if (fj > funcbufptr) | ||
399 | memmove(fnw, funcbufptr, fj - funcbufptr); | ||
400 | for (k = 0; k < j; k++) | ||
401 | if (func_table[k]) | ||
402 | func_table[k] = fnw + (func_table[k] - funcbufptr); | ||
403 | |||
404 | if (first_free > fj) { | ||
405 | memmove(fnw + (fj - funcbufptr) + delta, fj, first_free - fj); | ||
406 | for (k = j; k < MAX_NR_FUNC; k++) | ||
407 | if (func_table[k]) | ||
408 | func_table[k] = fnw + (func_table[k] - funcbufptr) + delta; | ||
409 | } | ||
410 | if (funcbufptr != func_buf) | ||
411 | kfree(funcbufptr); | ||
412 | funcbufptr = fnw; | ||
413 | funcbufleft = funcbufleft - delta + sz - funcbufsize; | ||
414 | funcbufsize = sz; | ||
415 | } | ||
416 | strcpy(func_table[i], kbs->kb_string); | ||
417 | break; | ||
418 | } | ||
419 | ret = 0; | ||
420 | reterr: | ||
421 | kfree(kbs); | ||
422 | return ret; | ||
423 | } | ||
221 | 424 | ||
222 | static inline int | 425 | static inline int |
223 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) | 426 | do_fontx_ioctl(int cmd, struct consolefontdesc __user *user_cfd, int perm, struct console_font_op *op) |
@@ -294,6 +497,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
294 | { | 497 | { |
295 | struct vc_data *vc = tty->driver_data; | 498 | struct vc_data *vc = tty->driver_data; |
296 | struct console_font_op op; /* used in multiple places here */ | 499 | struct console_font_op op; /* used in multiple places here */ |
500 | struct kbd_struct * kbd; | ||
297 | unsigned int console; | 501 | unsigned int console; |
298 | unsigned char ucval; | 502 | unsigned char ucval; |
299 | unsigned int uival; | 503 | unsigned int uival; |
@@ -303,6 +507,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
303 | 507 | ||
304 | console = vc->vc_num; | 508 | console = vc->vc_num; |
305 | 509 | ||
510 | tty_lock(); | ||
306 | 511 | ||
307 | if (!vc_cons_allocated(console)) { /* impossible? */ | 512 | if (!vc_cons_allocated(console)) { /* impossible? */ |
308 | ret = -ENOIOCTLCMD; | 513 | ret = -ENOIOCTLCMD; |
@@ -318,18 +523,19 @@ int vt_ioctl(struct tty_struct *tty, | |||
318 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) | 523 | if (current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG)) |
319 | perm = 1; | 524 | perm = 1; |
320 | 525 | ||
526 | kbd = kbd_table + console; | ||
321 | switch (cmd) { | 527 | switch (cmd) { |
322 | case TIOCLINUX: | 528 | case TIOCLINUX: |
323 | ret = tioclinux(tty, arg); | 529 | ret = tioclinux(tty, arg); |
324 | break; | 530 | break; |
325 | case KIOCSOUND: | 531 | case KIOCSOUND: |
326 | if (!perm) | 532 | if (!perm) |
327 | return -EPERM; | 533 | goto eperm; |
328 | /* | 534 | /* |
329 | * The use of PIT_TICK_RATE is historic, it used to be | 535 | * The use of PIT_TICK_RATE is historic, it used to be |
330 | * the platform-dependent CLOCK_TICK_RATE between 2.6.12 | 536 | * the platform-dependent CLOCK_TICK_RATE between 2.6.12 |
331 | * and 2.6.36, which was a minor but unfortunate ABI | 537 | * and 2.6.36, which was a minor but unfortunate ABI |
332 | * change. kd_mksound is locked by the input layer. | 538 | * change. |
333 | */ | 539 | */ |
334 | if (arg) | 540 | if (arg) |
335 | arg = PIT_TICK_RATE / arg; | 541 | arg = PIT_TICK_RATE / arg; |
@@ -338,7 +544,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
338 | 544 | ||
339 | case KDMKTONE: | 545 | case KDMKTONE: |
340 | if (!perm) | 546 | if (!perm) |
341 | return -EPERM; | 547 | goto eperm; |
342 | { | 548 | { |
343 | unsigned int ticks, count; | 549 | unsigned int ticks, count; |
344 | 550 | ||
@@ -356,11 +562,10 @@ int vt_ioctl(struct tty_struct *tty, | |||
356 | 562 | ||
357 | case KDGKBTYPE: | 563 | case KDGKBTYPE: |
358 | /* | 564 | /* |
359 | * this is naïve. | 565 | * this is naive. |
360 | */ | 566 | */ |
361 | ucval = KB_101; | 567 | ucval = KB_101; |
362 | ret = put_user(ucval, (char __user *)arg); | 568 | goto setchar; |
363 | break; | ||
364 | 569 | ||
365 | /* | 570 | /* |
366 | * These cannot be implemented on any machine that implements | 571 | * These cannot be implemented on any machine that implements |
@@ -374,8 +579,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
374 | /* | 579 | /* |
375 | * KDADDIO and KDDELIO may be able to add ports beyond what | 580 | * KDADDIO and KDDELIO may be able to add ports beyond what |
376 | * we reject here, but to be safe... | 581 | * we reject here, but to be safe... |
377 | * | ||
378 | * These are locked internally via sys_ioperm | ||
379 | */ | 582 | */ |
380 | if (arg < GPFIRST || arg > GPLAST) { | 583 | if (arg < GPFIRST || arg > GPLAST) { |
381 | ret = -EINVAL; | 584 | ret = -EINVAL; |
@@ -398,7 +601,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
398 | struct kbd_repeat kbrep; | 601 | struct kbd_repeat kbrep; |
399 | 602 | ||
400 | if (!capable(CAP_SYS_TTY_CONFIG)) | 603 | if (!capable(CAP_SYS_TTY_CONFIG)) |
401 | return -EPERM; | 604 | goto eperm; |
402 | 605 | ||
403 | if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { | 606 | if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { |
404 | ret = -EFAULT; | 607 | ret = -EFAULT; |
@@ -422,7 +625,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
422 | * need to restore their engine state. --BenH | 625 | * need to restore their engine state. --BenH |
423 | */ | 626 | */ |
424 | if (!perm) | 627 | if (!perm) |
425 | return -EPERM; | 628 | goto eperm; |
426 | switch (arg) { | 629 | switch (arg) { |
427 | case KD_GRAPHICS: | 630 | case KD_GRAPHICS: |
428 | break; | 631 | break; |
@@ -435,7 +638,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
435 | ret = -EINVAL; | 638 | ret = -EINVAL; |
436 | goto out; | 639 | goto out; |
437 | } | 640 | } |
438 | /* FIXME: this needs the console lock extending */ | ||
439 | if (vc->vc_mode == (unsigned char) arg) | 641 | if (vc->vc_mode == (unsigned char) arg) |
440 | break; | 642 | break; |
441 | vc->vc_mode = (unsigned char) arg; | 643 | vc->vc_mode = (unsigned char) arg; |
@@ -467,26 +669,69 @@ int vt_ioctl(struct tty_struct *tty, | |||
467 | 669 | ||
468 | case KDSKBMODE: | 670 | case KDSKBMODE: |
469 | if (!perm) | 671 | if (!perm) |
470 | return -EPERM; | 672 | goto eperm; |
471 | ret = vt_do_kdskbmode(console, arg); | 673 | switch(arg) { |
472 | if (ret == 0) | 674 | case K_RAW: |
473 | tty_ldisc_flush(tty); | 675 | kbd->kbdmode = VC_RAW; |
676 | break; | ||
677 | case K_MEDIUMRAW: | ||
678 | kbd->kbdmode = VC_MEDIUMRAW; | ||
679 | break; | ||
680 | case K_XLATE: | ||
681 | kbd->kbdmode = VC_XLATE; | ||
682 | compute_shiftstate(); | ||
683 | break; | ||
684 | case K_UNICODE: | ||
685 | kbd->kbdmode = VC_UNICODE; | ||
686 | compute_shiftstate(); | ||
687 | break; | ||
688 | case K_OFF: | ||
689 | kbd->kbdmode = VC_OFF; | ||
690 | break; | ||
691 | default: | ||
692 | ret = -EINVAL; | ||
693 | goto out; | ||
694 | } | ||
695 | tty_ldisc_flush(tty); | ||
474 | break; | 696 | break; |
475 | 697 | ||
476 | case KDGKBMODE: | 698 | case KDGKBMODE: |
477 | uival = vt_do_kdgkbmode(console); | 699 | switch (kbd->kbdmode) { |
478 | ret = put_user(uival, (int __user *)arg); | 700 | case VC_RAW: |
479 | break; | 701 | uival = K_RAW; |
702 | break; | ||
703 | case VC_MEDIUMRAW: | ||
704 | uival = K_MEDIUMRAW; | ||
705 | break; | ||
706 | case VC_UNICODE: | ||
707 | uival = K_UNICODE; | ||
708 | break; | ||
709 | case VC_OFF: | ||
710 | uival = K_OFF; | ||
711 | break; | ||
712 | default: | ||
713 | uival = K_XLATE; | ||
714 | break; | ||
715 | } | ||
716 | goto setint; | ||
480 | 717 | ||
481 | /* this could be folded into KDSKBMODE, but for compatibility | 718 | /* this could be folded into KDSKBMODE, but for compatibility |
482 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ | 719 | reasons it is not so easy to fold KDGKBMETA into KDGKBMODE */ |
483 | case KDSKBMETA: | 720 | case KDSKBMETA: |
484 | ret = vt_do_kdskbmeta(console, arg); | 721 | switch(arg) { |
722 | case K_METABIT: | ||
723 | clr_vc_kbd_mode(kbd, VC_META); | ||
724 | break; | ||
725 | case K_ESCPREFIX: | ||
726 | set_vc_kbd_mode(kbd, VC_META); | ||
727 | break; | ||
728 | default: | ||
729 | ret = -EINVAL; | ||
730 | } | ||
485 | break; | 731 | break; |
486 | 732 | ||
487 | case KDGKBMETA: | 733 | case KDGKBMETA: |
488 | /* FIXME: should review whether this is worth locking */ | 734 | uival = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); |
489 | uival = vt_do_kdgkbmeta(console); | ||
490 | setint: | 735 | setint: |
491 | ret = put_user(uival, (int __user *)arg); | 736 | ret = put_user(uival, (int __user *)arg); |
492 | break; | 737 | break; |
@@ -495,35 +740,133 @@ int vt_ioctl(struct tty_struct *tty, | |||
495 | case KDSETKEYCODE: | 740 | case KDSETKEYCODE: |
496 | if(!capable(CAP_SYS_TTY_CONFIG)) | 741 | if(!capable(CAP_SYS_TTY_CONFIG)) |
497 | perm = 0; | 742 | perm = 0; |
498 | ret = vt_do_kbkeycode_ioctl(cmd, up, perm); | 743 | ret = do_kbkeycode_ioctl(cmd, up, perm); |
499 | break; | 744 | break; |
500 | 745 | ||
501 | case KDGKBENT: | 746 | case KDGKBENT: |
502 | case KDSKBENT: | 747 | case KDSKBENT: |
503 | ret = vt_do_kdsk_ioctl(cmd, up, perm, console); | 748 | ret = do_kdsk_ioctl(cmd, up, perm, kbd); |
504 | break; | 749 | break; |
505 | 750 | ||
506 | case KDGKBSENT: | 751 | case KDGKBSENT: |
507 | case KDSKBSENT: | 752 | case KDSKBSENT: |
508 | ret = vt_do_kdgkb_ioctl(cmd, up, perm); | 753 | ret = do_kdgkb_ioctl(cmd, up, perm); |
509 | break; | 754 | break; |
510 | 755 | ||
511 | /* Diacritical processing. Handled in keyboard.c as it has | ||
512 | to operate on the keyboard locks and structures */ | ||
513 | case KDGKBDIACR: | 756 | case KDGKBDIACR: |
757 | { | ||
758 | struct kbdiacrs __user *a = up; | ||
759 | struct kbdiacr diacr; | ||
760 | int i; | ||
761 | |||
762 | if (put_user(accent_table_size, &a->kb_cnt)) { | ||
763 | ret = -EFAULT; | ||
764 | break; | ||
765 | } | ||
766 | for (i = 0; i < accent_table_size; i++) { | ||
767 | diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); | ||
768 | diacr.base = conv_uni_to_8bit(accent_table[i].base); | ||
769 | diacr.result = conv_uni_to_8bit(accent_table[i].result); | ||
770 | if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) { | ||
771 | ret = -EFAULT; | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | break; | ||
776 | } | ||
514 | case KDGKBDIACRUC: | 777 | case KDGKBDIACRUC: |
778 | { | ||
779 | struct kbdiacrsuc __user *a = up; | ||
780 | |||
781 | if (put_user(accent_table_size, &a->kb_cnt)) | ||
782 | ret = -EFAULT; | ||
783 | else if (copy_to_user(a->kbdiacruc, accent_table, | ||
784 | accent_table_size*sizeof(struct kbdiacruc))) | ||
785 | ret = -EFAULT; | ||
786 | break; | ||
787 | } | ||
788 | |||
515 | case KDSKBDIACR: | 789 | case KDSKBDIACR: |
790 | { | ||
791 | struct kbdiacrs __user *a = up; | ||
792 | struct kbdiacr diacr; | ||
793 | unsigned int ct; | ||
794 | int i; | ||
795 | |||
796 | if (!perm) | ||
797 | goto eperm; | ||
798 | if (get_user(ct,&a->kb_cnt)) { | ||
799 | ret = -EFAULT; | ||
800 | break; | ||
801 | } | ||
802 | if (ct >= MAX_DIACR) { | ||
803 | ret = -EINVAL; | ||
804 | break; | ||
805 | } | ||
806 | accent_table_size = ct; | ||
807 | for (i = 0; i < ct; i++) { | ||
808 | if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) { | ||
809 | ret = -EFAULT; | ||
810 | break; | ||
811 | } | ||
812 | accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); | ||
813 | accent_table[i].base = conv_8bit_to_uni(diacr.base); | ||
814 | accent_table[i].result = conv_8bit_to_uni(diacr.result); | ||
815 | } | ||
816 | break; | ||
817 | } | ||
818 | |||
516 | case KDSKBDIACRUC: | 819 | case KDSKBDIACRUC: |
517 | ret = vt_do_diacrit(cmd, up, perm); | 820 | { |
821 | struct kbdiacrsuc __user *a = up; | ||
822 | unsigned int ct; | ||
823 | |||
824 | if (!perm) | ||
825 | goto eperm; | ||
826 | if (get_user(ct,&a->kb_cnt)) { | ||
827 | ret = -EFAULT; | ||
828 | break; | ||
829 | } | ||
830 | if (ct >= MAX_DIACR) { | ||
831 | ret = -EINVAL; | ||
832 | break; | ||
833 | } | ||
834 | accent_table_size = ct; | ||
835 | if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) | ||
836 | ret = -EFAULT; | ||
518 | break; | 837 | break; |
838 | } | ||
519 | 839 | ||
520 | /* the ioctls below read/set the flags usually shown in the leds */ | 840 | /* the ioctls below read/set the flags usually shown in the leds */ |
521 | /* don't use them - they will go away without warning */ | 841 | /* don't use them - they will go away without warning */ |
522 | case KDGKBLED: | 842 | case KDGKBLED: |
843 | ucval = kbd->ledflagstate | (kbd->default_ledflagstate << 4); | ||
844 | goto setchar; | ||
845 | |||
523 | case KDSKBLED: | 846 | case KDSKBLED: |
847 | if (!perm) | ||
848 | goto eperm; | ||
849 | if (arg & ~0x77) { | ||
850 | ret = -EINVAL; | ||
851 | break; | ||
852 | } | ||
853 | kbd->ledflagstate = (arg & 7); | ||
854 | kbd->default_ledflagstate = ((arg >> 4) & 7); | ||
855 | set_leds(); | ||
856 | break; | ||
857 | |||
858 | /* the ioctls below only set the lights, not the functions */ | ||
859 | /* for those, see KDGKBLED and KDSKBLED above */ | ||
524 | case KDGETLED: | 860 | case KDGETLED: |
861 | ucval = getledstate(); | ||
862 | setchar: | ||
863 | ret = put_user(ucval, (char __user *)arg); | ||
864 | break; | ||
865 | |||
525 | case KDSETLED: | 866 | case KDSETLED: |
526 | ret = vt_do_kdskled(console, cmd, arg, perm); | 867 | if (!perm) |
868 | goto eperm; | ||
869 | setledstate(kbd, arg); | ||
527 | break; | 870 | break; |
528 | 871 | ||
529 | /* | 872 | /* |
@@ -536,7 +879,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
536 | case KDSIGACCEPT: | 879 | case KDSIGACCEPT: |
537 | { | 880 | { |
538 | if (!perm || !capable(CAP_KILL)) | 881 | if (!perm || !capable(CAP_KILL)) |
539 | return -EPERM; | 882 | goto eperm; |
540 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) | 883 | if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) |
541 | ret = -EINVAL; | 884 | ret = -EINVAL; |
542 | else { | 885 | else { |
@@ -554,7 +897,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
554 | struct vt_mode tmp; | 897 | struct vt_mode tmp; |
555 | 898 | ||
556 | if (!perm) | 899 | if (!perm) |
557 | return -EPERM; | 900 | goto eperm; |
558 | if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { | 901 | if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { |
559 | ret = -EFAULT; | 902 | ret = -EFAULT; |
560 | goto out; | 903 | goto out; |
@@ -600,7 +943,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
600 | struct vt_stat __user *vtstat = up; | 943 | struct vt_stat __user *vtstat = up; |
601 | unsigned short state, mask; | 944 | unsigned short state, mask; |
602 | 945 | ||
603 | /* Review: FIXME: Console lock ? */ | ||
604 | if (put_user(fg_console + 1, &vtstat->v_active)) | 946 | if (put_user(fg_console + 1, &vtstat->v_active)) |
605 | ret = -EFAULT; | 947 | ret = -EFAULT; |
606 | else { | 948 | else { |
@@ -618,7 +960,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
618 | * Returns the first available (non-opened) console. | 960 | * Returns the first available (non-opened) console. |
619 | */ | 961 | */ |
620 | case VT_OPENQRY: | 962 | case VT_OPENQRY: |
621 | /* FIXME: locking ? - but then this is a stupid API */ | ||
622 | for (i = 0; i < MAX_NR_CONSOLES; ++i) | 963 | for (i = 0; i < MAX_NR_CONSOLES; ++i) |
623 | if (! VT_IS_IN_USE(i)) | 964 | if (! VT_IS_IN_USE(i)) |
624 | break; | 965 | break; |
@@ -632,7 +973,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
632 | */ | 973 | */ |
633 | case VT_ACTIVATE: | 974 | case VT_ACTIVATE: |
634 | if (!perm) | 975 | if (!perm) |
635 | return -EPERM; | 976 | goto eperm; |
636 | if (arg == 0 || arg > MAX_NR_CONSOLES) | 977 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
637 | ret = -ENXIO; | 978 | ret = -ENXIO; |
638 | else { | 979 | else { |
@@ -651,7 +992,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
651 | struct vt_setactivate vsa; | 992 | struct vt_setactivate vsa; |
652 | 993 | ||
653 | if (!perm) | 994 | if (!perm) |
654 | return -EPERM; | 995 | goto eperm; |
655 | 996 | ||
656 | if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, | 997 | if (copy_from_user(&vsa, (struct vt_setactivate __user *)arg, |
657 | sizeof(struct vt_setactivate))) { | 998 | sizeof(struct vt_setactivate))) { |
@@ -679,7 +1020,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
679 | if (ret) | 1020 | if (ret) |
680 | break; | 1021 | break; |
681 | /* Commence switch and lock */ | 1022 | /* Commence switch and lock */ |
682 | /* Review set_console locks */ | ||
683 | set_console(vsa.console); | 1023 | set_console(vsa.console); |
684 | } | 1024 | } |
685 | break; | 1025 | break; |
@@ -690,7 +1030,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
690 | */ | 1030 | */ |
691 | case VT_WAITACTIVE: | 1031 | case VT_WAITACTIVE: |
692 | if (!perm) | 1032 | if (!perm) |
693 | return -EPERM; | 1033 | goto eperm; |
694 | if (arg == 0 || arg > MAX_NR_CONSOLES) | 1034 | if (arg == 0 || arg > MAX_NR_CONSOLES) |
695 | ret = -ENXIO; | 1035 | ret = -ENXIO; |
696 | else | 1036 | else |
@@ -709,17 +1049,16 @@ int vt_ioctl(struct tty_struct *tty, | |||
709 | */ | 1049 | */ |
710 | case VT_RELDISP: | 1050 | case VT_RELDISP: |
711 | if (!perm) | 1051 | if (!perm) |
712 | return -EPERM; | 1052 | goto eperm; |
713 | 1053 | ||
714 | console_lock(); | ||
715 | if (vc->vt_mode.mode != VT_PROCESS) { | 1054 | if (vc->vt_mode.mode != VT_PROCESS) { |
716 | console_unlock(); | ||
717 | ret = -EINVAL; | 1055 | ret = -EINVAL; |
718 | break; | 1056 | break; |
719 | } | 1057 | } |
720 | /* | 1058 | /* |
721 | * Switching-from response | 1059 | * Switching-from response |
722 | */ | 1060 | */ |
1061 | console_lock(); | ||
723 | if (vc->vt_newvt >= 0) { | 1062 | if (vc->vt_newvt >= 0) { |
724 | if (arg == 0) | 1063 | if (arg == 0) |
725 | /* | 1064 | /* |
@@ -796,7 +1135,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
796 | 1135 | ||
797 | ushort ll,cc; | 1136 | ushort ll,cc; |
798 | if (!perm) | 1137 | if (!perm) |
799 | return -EPERM; | 1138 | goto eperm; |
800 | if (get_user(ll, &vtsizes->v_rows) || | 1139 | if (get_user(ll, &vtsizes->v_rows) || |
801 | get_user(cc, &vtsizes->v_cols)) | 1140 | get_user(cc, &vtsizes->v_cols)) |
802 | ret = -EFAULT; | 1141 | ret = -EFAULT; |
@@ -807,7 +1146,6 @@ int vt_ioctl(struct tty_struct *tty, | |||
807 | 1146 | ||
808 | if (vc) { | 1147 | if (vc) { |
809 | vc->vc_resize_user = 1; | 1148 | vc->vc_resize_user = 1; |
810 | /* FIXME: review v tty lock */ | ||
811 | vc_resize(vc_cons[i].d, cc, ll); | 1149 | vc_resize(vc_cons[i].d, cc, ll); |
812 | } | 1150 | } |
813 | } | 1151 | } |
@@ -821,7 +1159,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
821 | struct vt_consize __user *vtconsize = up; | 1159 | struct vt_consize __user *vtconsize = up; |
822 | ushort ll,cc,vlin,clin,vcol,ccol; | 1160 | ushort ll,cc,vlin,clin,vcol,ccol; |
823 | if (!perm) | 1161 | if (!perm) |
824 | return -EPERM; | 1162 | goto eperm; |
825 | if (!access_ok(VERIFY_READ, vtconsize, | 1163 | if (!access_ok(VERIFY_READ, vtconsize, |
826 | sizeof(struct vt_consize))) { | 1164 | sizeof(struct vt_consize))) { |
827 | ret = -EFAULT; | 1165 | ret = -EFAULT; |
@@ -877,7 +1215,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
877 | 1215 | ||
878 | case PIO_FONT: { | 1216 | case PIO_FONT: { |
879 | if (!perm) | 1217 | if (!perm) |
880 | return -EPERM; | 1218 | goto eperm; |
881 | op.op = KD_FONT_OP_SET; | 1219 | op.op = KD_FONT_OP_SET; |
882 | op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ | 1220 | op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ |
883 | op.width = 8; | 1221 | op.width = 8; |
@@ -918,7 +1256,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
918 | case PIO_FONTRESET: | 1256 | case PIO_FONTRESET: |
919 | { | 1257 | { |
920 | if (!perm) | 1258 | if (!perm) |
921 | return -EPERM; | 1259 | goto eperm; |
922 | 1260 | ||
923 | #ifdef BROKEN_GRAPHICS_PROGRAMS | 1261 | #ifdef BROKEN_GRAPHICS_PROGRAMS |
924 | /* With BROKEN_GRAPHICS_PROGRAMS defined, the default | 1262 | /* With BROKEN_GRAPHICS_PROGRAMS defined, the default |
@@ -932,9 +1270,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
932 | ret = con_font_op(vc_cons[fg_console].d, &op); | 1270 | ret = con_font_op(vc_cons[fg_console].d, &op); |
933 | if (ret) | 1271 | if (ret) |
934 | break; | 1272 | break; |
935 | console_lock(); | ||
936 | con_set_default_unimap(vc_cons[fg_console].d); | 1273 | con_set_default_unimap(vc_cons[fg_console].d); |
937 | console_unlock(); | ||
938 | break; | 1274 | break; |
939 | } | 1275 | } |
940 | #endif | 1276 | #endif |
@@ -946,7 +1282,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
946 | break; | 1282 | break; |
947 | } | 1283 | } |
948 | if (!perm && op.op != KD_FONT_OP_GET) | 1284 | if (!perm && op.op != KD_FONT_OP_GET) |
949 | return -EPERM; | 1285 | goto eperm; |
950 | ret = con_font_op(vc, &op); | 1286 | ret = con_font_op(vc, &op); |
951 | if (ret) | 1287 | if (ret) |
952 | break; | 1288 | break; |
@@ -980,7 +1316,7 @@ int vt_ioctl(struct tty_struct *tty, | |||
980 | case PIO_UNIMAPCLR: | 1316 | case PIO_UNIMAPCLR: |
981 | { struct unimapinit ui; | 1317 | { struct unimapinit ui; |
982 | if (!perm) | 1318 | if (!perm) |
983 | return -EPERM; | 1319 | goto eperm; |
984 | ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); | 1320 | ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); |
985 | if (ret) | 1321 | if (ret) |
986 | ret = -EFAULT; | 1322 | ret = -EFAULT; |
@@ -996,12 +1332,12 @@ int vt_ioctl(struct tty_struct *tty, | |||
996 | 1332 | ||
997 | case VT_LOCKSWITCH: | 1333 | case VT_LOCKSWITCH: |
998 | if (!capable(CAP_SYS_TTY_CONFIG)) | 1334 | if (!capable(CAP_SYS_TTY_CONFIG)) |
999 | return -EPERM; | 1335 | goto eperm; |
1000 | vt_dont_switch = 1; | 1336 | vt_dont_switch = 1; |
1001 | break; | 1337 | break; |
1002 | case VT_UNLOCKSWITCH: | 1338 | case VT_UNLOCKSWITCH: |
1003 | if (!capable(CAP_SYS_TTY_CONFIG)) | 1339 | if (!capable(CAP_SYS_TTY_CONFIG)) |
1004 | return -EPERM; | 1340 | goto eperm; |
1005 | vt_dont_switch = 0; | 1341 | vt_dont_switch = 0; |
1006 | break; | 1342 | break; |
1007 | case VT_GETHIFONTMASK: | 1343 | case VT_GETHIFONTMASK: |
@@ -1015,13 +1351,17 @@ int vt_ioctl(struct tty_struct *tty, | |||
1015 | ret = -ENOIOCTLCMD; | 1351 | ret = -ENOIOCTLCMD; |
1016 | } | 1352 | } |
1017 | out: | 1353 | out: |
1354 | tty_unlock(); | ||
1018 | return ret; | 1355 | return ret; |
1356 | eperm: | ||
1357 | ret = -EPERM; | ||
1358 | goto out; | ||
1019 | } | 1359 | } |
1020 | 1360 | ||
1021 | void reset_vc(struct vc_data *vc) | 1361 | void reset_vc(struct vc_data *vc) |
1022 | { | 1362 | { |
1023 | vc->vc_mode = KD_TEXT; | 1363 | vc->vc_mode = KD_TEXT; |
1024 | vt_reset_unicode(vc->vc_num); | 1364 | kbd_table[vc->vc_num].kbdmode = default_utf8 ? VC_UNICODE : VC_XLATE; |
1025 | vc->vt_mode.mode = VT_AUTO; | 1365 | vc->vt_mode.mode = VT_AUTO; |
1026 | vc->vt_mode.waitv = 0; | 1366 | vc->vt_mode.waitv = 0; |
1027 | vc->vt_mode.relsig = 0; | 1367 | vc->vt_mode.relsig = 0; |
@@ -1044,7 +1384,6 @@ void vc_SAK(struct work_struct *work) | |||
1044 | console_lock(); | 1384 | console_lock(); |
1045 | vc = vc_con->d; | 1385 | vc = vc_con->d; |
1046 | if (vc) { | 1386 | if (vc) { |
1047 | /* FIXME: review tty ref counting */ | ||
1048 | tty = vc->port.tty; | 1387 | tty = vc->port.tty; |
1049 | /* | 1388 | /* |
1050 | * SAK should also work in all raw modes and reset | 1389 | * SAK should also work in all raw modes and reset |
@@ -1124,6 +1463,7 @@ compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, | |||
1124 | if (!perm && op->op != KD_FONT_OP_GET) | 1463 | if (!perm && op->op != KD_FONT_OP_GET) |
1125 | return -EPERM; | 1464 | return -EPERM; |
1126 | op->data = compat_ptr(((struct compat_console_font_op *)op)->data); | 1465 | op->data = compat_ptr(((struct compat_console_font_op *)op)->data); |
1466 | op->flags |= KD_FONT_FLAG_OLD; | ||
1127 | i = con_font_op(vc, op); | 1467 | i = con_font_op(vc, op); |
1128 | if (i) | 1468 | if (i) |
1129 | return i; | 1469 | return i; |
@@ -1177,6 +1517,8 @@ long vt_compat_ioctl(struct tty_struct *tty, | |||
1177 | 1517 | ||
1178 | console = vc->vc_num; | 1518 | console = vc->vc_num; |
1179 | 1519 | ||
1520 | tty_lock(); | ||
1521 | |||
1180 | if (!vc_cons_allocated(console)) { /* impossible? */ | 1522 | if (!vc_cons_allocated(console)) { /* impossible? */ |
1181 | ret = -ENOIOCTLCMD; | 1523 | ret = -ENOIOCTLCMD; |
1182 | goto out; | 1524 | goto out; |
@@ -1242,9 +1584,11 @@ long vt_compat_ioctl(struct tty_struct *tty, | |||
1242 | goto fallback; | 1584 | goto fallback; |
1243 | } | 1585 | } |
1244 | out: | 1586 | out: |
1587 | tty_unlock(); | ||
1245 | return ret; | 1588 | return ret; |
1246 | 1589 | ||
1247 | fallback: | 1590 | fallback: |
1591 | tty_unlock(); | ||
1248 | return vt_ioctl(tty, cmd, arg); | 1592 | return vt_ioctl(tty, cmd, arg); |
1249 | } | 1593 | } |
1250 | 1594 | ||
@@ -1430,10 +1774,13 @@ int vt_move_to_console(unsigned int vt, int alloc) | |||
1430 | return -EIO; | 1774 | return -EIO; |
1431 | } | 1775 | } |
1432 | console_unlock(); | 1776 | console_unlock(); |
1777 | tty_lock(); | ||
1433 | if (vt_waitactive(vt + 1)) { | 1778 | if (vt_waitactive(vt + 1)) { |
1434 | pr_debug("Suspend: Can't switch VCs."); | 1779 | pr_debug("Suspend: Can't switch VCs."); |
1780 | tty_unlock(); | ||
1435 | return -EINTR; | 1781 | return -EINTR; |
1436 | } | 1782 | } |
1783 | tty_unlock(); | ||
1437 | return prev; | 1784 | return prev; |
1438 | } | 1785 | } |
1439 | 1786 | ||