📄 consolemap.c
字号:
* * A font has at most 512 chars, usually 256. * But one font position may represent several Unicode chars. * A hashtable is somewhat of a pain to deal with, so use a * "paged table" instead. Simulation has shown the memory cost of * this 3-level paged table scheme to be comparable to a hash table. */extern u8 dfont_unicount[]; /* Defined in console_defmap.c */extern u16 dfont_unitable[];static void con_release_unimap(struct uni_pagedir *p){ u16 **p1; int i, j; if (p == dflt) dflt = NULL; for (i = 0; i < 32; i++) { if ((p1 = p->uni_pgdir[i]) != NULL) { for (j = 0; j < 32; j++) kfree(p1[j]); kfree(p1); } p->uni_pgdir[i] = NULL; } for (i = 0; i < 4; i++) { kfree(p->inverse_translations[i]); p->inverse_translations[i] = NULL; } if (p->inverse_trans_unicode) { kfree(p->inverse_trans_unicode); p->inverse_trans_unicode = NULL; }}void con_free_unimap(struct vc_data *vc){ struct uni_pagedir *p; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (!p) return; *vc->vc_uni_pagedir_loc = 0; if (--p->refcount) return; con_release_unimap(p); kfree(p);} static int con_unify_unimap(struct vc_data *conp, struct uni_pagedir *p){ int i, j, k; struct uni_pagedir *q; for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons_allocated(i)) continue; q = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; if (!q || q == p || q->sum != p->sum) continue; for (j = 0; j < 32; j++) { u16 **p1, **q1; p1 = p->uni_pgdir[j]; q1 = q->uni_pgdir[j]; if (!p1 && !q1) continue; if (!p1 || !q1) break; for (k = 0; k < 32; k++) { if (!p1[k] && !q1[k]) continue; if (!p1[k] || !q1[k]) break; if (memcmp(p1[k], q1[k], 64*sizeof(u16))) break; } if (k < 32) break; } if (j == 32) { q->refcount++; *conp->vc_uni_pagedir_loc = (unsigned long)q; con_release_unimap(p); kfree(p); return 1; } } return 0;}static intcon_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos){ int i, n; u16 **p1, *p2; if (!(p1 = p->uni_pgdir[n = unicode >> 11])) { p1 = p->uni_pgdir[n] = kmalloc(32*sizeof(u16 *), GFP_KERNEL); if (!p1) return -ENOMEM; for (i = 0; i < 32; i++) p1[i] = NULL; } if (!(p2 = p1[n = (unicode >> 6) & 0x1f])) { p2 = p1[n] = kmalloc(64*sizeof(u16), GFP_KERNEL); if (!p2) return -ENOMEM; memset(p2, 0xff, 64*sizeof(u16)); /* No glyphs for the characters (yet) */ } p2[unicode & 0x3f] = fontpos; p->sum += (fontpos << 20) + unicode; return 0;}/* ui is a leftover from using a hashtable, but might be used again */int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui){ struct uni_pagedir *p, *q; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p && p->readonly) return -EIO; if (!p || --p->refcount) { q = kzalloc(sizeof(*p), GFP_KERNEL); if (!q) { if (p) p->refcount++; return -ENOMEM; } q->refcount=1; *vc->vc_uni_pagedir_loc = (unsigned long)q; } else { if (p == dflt) dflt = NULL; p->refcount++; p->sum = 0; con_release_unimap(p); } return 0;}int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list){ int err = 0, err1, i; struct uni_pagedir *p, *q; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p->readonly) return -EIO; if (!ct) return 0; if (p->refcount > 1) { int j, k; u16 **p1, *p2, l; err1 = con_clear_unimap(vc, NULL); if (err1) return err1; q = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0, l = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) if ((p2 = p1[j])) for (k = 0; k < 64; k++, l++) if (p2[k] != 0xffff) { 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; } } p = q; } else if (p == dflt) dflt = NULL; while (ct--) { unsigned short unicode, fontpos; __get_user(unicode, &list->unicode); __get_user(fontpos, &list->fontpos); if ((err1 = con_insert_unipair(p, unicode,fontpos)) != 0) err = err1; list++; } 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_trans_unicode(vc, p); return err;}/* Loads the unimap for the hardware font, as defined in uni_hash.tbl. The representation used was the most compact I could come up with. This routine is executed at sys_setup time, and when the PIO_FONTRESET ioctl is called. */int con_set_default_unimap(struct vc_data *vc){ int i, j, err = 0, err1; u16 *q; struct uni_pagedir *p; if (dflt) { p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p == dflt) return 0; dflt->refcount++; *vc->vc_uni_pagedir_loc = (unsigned long)dflt; if (p && --p->refcount) { con_release_unimap(p); kfree(p); } return 0; } /* The default font is always 256 characters */ err = con_clear_unimap(vc, NULL); if (err) return err; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; q = dfont_unitable; for (i = 0; i < 256; i++) for (j = dfont_unicount[i]; j; j--) { err1 = con_insert_unipair(p, *(q++), i); if (err1) err = err1; } if (con_unify_unimap(vc, p)) { dflt = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; return err; } for (i = 0; i <= 3; i++) set_inverse_transl(vc, p, i); /* Update all inverse translations */ set_inverse_trans_unicode(vc, p); dflt = p; return err;}EXPORT_SYMBOL(con_set_default_unimap);int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc){ struct uni_pagedir *q; if (!*src_vc->vc_uni_pagedir_loc) return -EINVAL; if (*dst_vc->vc_uni_pagedir_loc == *src_vc->vc_uni_pagedir_loc) return 0; con_free_unimap(dst_vc); q = (struct uni_pagedir *)*src_vc->vc_uni_pagedir_loc; q->refcount++; *dst_vc->vc_uni_pagedir_loc = (long)q; return 0;}int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list){ int i, j, k, ect; u16 **p1, *p2; struct uni_pagedir *p; ect = 0; if (*vc->vc_uni_pagedir_loc) { p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; for (i = 0; i < 32; i++) if ((p1 = p->uni_pgdir[i])) for (j = 0; j < 32; j++) if ((p2 = *(p1++))) for (k = 0; k < 64; k++) { if (*p2 < MAX_GLYPH && ect++ < ct) { __put_user((u_short)((i<<11)+(j<<6)+k), &list->unicode); __put_user((u_short) *p2, &list->fontpos); list++; } p2++; } } __put_user(ect, uct); return ((ect <= ct) ? 0 : -ENOMEM);}void con_protect_unimap(struct vc_data *vc, int rdonly){ struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; if (p) p->readonly = rdonly;}/* * Always use USER_MAP. These functions are used by the keyboard, * which shouldn't be affected by G0/G1 switching, etc. * If the user map still contains default values, i.e. the * direct-to-font mapping, then assume user is using Latin1. *//* may be called during an interrupt */u32 conv_8bit_to_uni(unsigned char c){ unsigned short uni = translations[USER_MAP][c]; return uni == (0xf000 | c) ? c : uni;}int conv_uni_to_8bit(u32 uni){ int c; for (c = 0; c < 0x100; c++) if (translations[USER_MAP][c] == uni || (translations[USER_MAP][c] == (c | 0xf000) && uni == c)) return c; return -1;}intconv_uni_to_pc(struct vc_data *conp, long ucs) { int h; u16 **p1, *p2; struct uni_pagedir *p; /* Only 16-bit codes supported at this time */ if (ucs > 0xffff) return -4; /* Not found */ else if (ucs < 0x20) return -1; /* Not a printable character */ else if (ucs == 0xfeff || (ucs >= 0x200b && ucs <= 0x200f)) return -2; /* Zero-width space */ /* * UNI_DIRECT_BASE indicates the start of the region in the User Zone * which always has a 1:1 mapping to the currently loaded font. The * UNI_DIRECT_MASK indicates the bit span of the region. */ else if ((ucs & ~UNI_DIRECT_MASK) == UNI_DIRECT_BASE) return ucs & UNI_DIRECT_MASK; if (!*conp->vc_uni_pagedir_loc) return -3; p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc; if ((p1 = p->uni_pgdir[ucs >> 11]) && (p2 = p1[(ucs >> 6) & 0x1f]) && (h = p2[ucs & 0x3f]) < MAX_GLYPH) return h; return -4; /* not found */}/* * This is called at sys_setup time, after memory and the console are * initialized. It must be possible to call kmalloc(..., GFP_KERNEL) * from this function, hence the call from sys_setup. */void __init console_map_init(void){ int i; for (i = 0; i < MAX_NR_CONSOLES; i++) if (vc_cons_allocated(i) && !*vc_cons[i].d->vc_uni_pagedir_loc) con_set_default_unimap(vc_cons[i].d);}EXPORT_SYMBOL(con_copy_unimap);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -