aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/vt/consolemap.c51
1 files changed, 43 insertions, 8 deletions
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index a0f3d6c4d39d..8308fc7cdc26 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -516,6 +516,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
516 int err = 0, err1, i; 516 int err = 0, err1, i;
517 struct uni_pagedir *p, *q; 517 struct uni_pagedir *p, *q;
518 518
519 /* Save original vc_unipagdir_loc in case we allocate a new one */
519 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 520 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
520 if (p->readonly) return -EIO; 521 if (p->readonly) return -EIO;
521 522
@@ -528,26 +529,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
528 err1 = con_clear_unimap(vc, NULL); 529 err1 = con_clear_unimap(vc, NULL);
529 if (err1) return err1; 530 if (err1) return err1;
530 531
532 /*
533 * Since refcount was > 1, con_clear_unimap() allocated a
534 * a new uni_pagedir for this vc. Re: p != q
535 */
531 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 536 q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
532 for (i = 0, l = 0; i < 32; i++) 537
538 /*
539 * uni_pgdir is a 32*32*64 table with rows allocated
540 * when its first entry is added. The unicode value must
541 * still be incremented for empty rows. We are copying
542 * entries from "p" (old) to "q" (new).
543 */
544 l = 0; /* unicode value */
545 for (i = 0; i < 32; i++)
533 if ((p1 = p->uni_pgdir[i])) 546 if ((p1 = p->uni_pgdir[i]))
534 for (j = 0; j < 32; j++) 547 for (j = 0; j < 32; j++)
535 if ((p2 = p1[j])) 548 if ((p2 = p1[j])) {
536 for (k = 0; k < 64; k++, l++) 549 for (k = 0; k < 64; k++, l++)
537 if (p2[k] != 0xffff) { 550 if (p2[k] != 0xffff) {
551 /*
552 * Found one, copy entry for unicode
553 * l with fontpos value p2[k].
554 */
538 err1 = con_insert_unipair(q, l, p2[k]); 555 err1 = con_insert_unipair(q, l, p2[k]);
539 if (err1) { 556 if (err1) {
540 p->refcount++; 557 p->refcount++;
541 *vc->vc_uni_pagedir_loc = (unsigned long)p; 558 *vc->vc_uni_pagedir_loc = (unsigned long)p;
542 con_release_unimap(q); 559 con_release_unimap(q);
543 kfree(q); 560 kfree(q);
544 return err1; 561 return err1;
545 } 562 }
546 } 563 }
547 p = q; 564 } else {
548 } else if (p == dflt) 565 /* Account for row of 64 empty entries */
566 l += 64;
567 }
568 else
569 /* Account for empty table */
570 l += 32 * 64;
571
572 /*
573 * Finished copying font table, set vc_uni_pagedir to new table
574 */
575 p = q;
576 } else if (p == dflt) {
549 dflt = NULL; 577 dflt = NULL;
550 578 }
579
580 /*
581 * Insert user specified unicode pairs into new table.
582 */
551 while (ct--) { 583 while (ct--) {
552 unsigned short unicode, fontpos; 584 unsigned short unicode, fontpos;
553 __get_user(unicode, &list->unicode); 585 __get_user(unicode, &list->unicode);
@@ -557,11 +589,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
557 list++; 589 list++;
558 } 590 }
559 591
592 /*
593 * Merge with fontmaps of any other virtual consoles.
594 */
560 if (con_unify_unimap(vc, p)) 595 if (con_unify_unimap(vc, p))
561 return err; 596 return err;
562 597
563 for (i = 0; i <= 3; i++) 598 for (i = 0; i <= 3; i++)
564 set_inverse_transl(vc, p, i); /* Update all inverse translations */ 599 set_inverse_transl(vc, p, i); /* Update inverse translations */
565 set_inverse_trans_unicode(vc, p); 600 set_inverse_trans_unicode(vc, p);
566 601
567 return err; 602 return err;