Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / drivers / tty / vt / consolemap.c
index 45d3e80..fb95acc 100644 (file)
@@ -516,7 +516,10 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
        int err = 0, err1, i;
        struct uni_pagedir *p, *q;
 
+       /* Save original vc_unipagdir_loc in case we allocate a new one */
        p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
+       if (!p)
+               return -EINVAL;
        if (p->readonly) return -EIO;
        
        if (!ct) return 0;
@@ -528,26 +531,57 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
                err1 = con_clear_unimap(vc, NULL);
                if (err1) return err1;
                
+               /*
+                * Since refcount was > 1, con_clear_unimap() allocated a
+                * a new uni_pagedir for this vc.  Re: p != q
+                */
                q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
-               for (i = 0, l = 0; i < 32; i++)
+
+               /*
+                * uni_pgdir is a 32*32*64 table with rows allocated
+                * when its first entry is added.  The unicode value must
+                * still be incremented for empty rows.  We are copying
+                * entries from "p" (old) to "q" (new).
+                */
+               l = 0;          /* unicode value */
+               for (i = 0; i < 32; i++)
                if ((p1 = p->uni_pgdir[i]))
                        for (j = 0; j < 32; j++)
-                       if ((p2 = p1[j]))
+                       if ((p2 = p1[j])) {
                                for (k = 0; k < 64; k++, l++)
                                if (p2[k] != 0xffff) {
+                                       /*
+                                        * Found one, copy entry for unicode
+                                        * l with fontpos value p2[k].
+                                        */
                                        err1 = con_insert_unipair(q, l, p2[k]);
                                        if (err1) {
                                                p->refcount++;
                                                *vc->vc_uni_pagedir_loc = (unsigned long)p;
                                                con_release_unimap(q);
                                                kfree(q);
-                                               return err1; 
+                                               return err1;
                                        }
-                               }
-               p = q;
-       } else if (p == dflt)
+                               }
+                       } else {
+                               /* Account for row of 64 empty entries */
+                               l += 64;
+                       }
+               else
+                       /* Account for empty table */
+                       l += 32 * 64;
+
+               /*
+                * Finished copying font table, set vc_uni_pagedir to new table
+                */
+               p = q;
+       } else if (p == dflt) {
                dflt = NULL;
-       
+       }
+
+       /*
+        * Insert user specified unicode pairs into new table.
+        */
        while (ct--) {
                unsigned short unicode, fontpos;
                __get_user(unicode, &list->unicode);
@@ -557,11 +591,14 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
                list++;
        }
        
+       /*
+        * Merge with fontmaps of any other virtual consoles.
+        */
        if (con_unify_unimap(vc, p))
                return err;
 
        for (i = 0; i <= 3; i++)
-               set_inverse_transl(vc, p, i); /* Update all inverse translations */
+               set_inverse_transl(vc, p, i); /* Update inverse translations */
        set_inverse_trans_unicode(vc, p);
   
        return err;