5 FONT ROM ドライバ

この章の目次へ

この章では ROM フォントの構造と PocketLinux のドライバの内部について説明します。

5.1 フォントの ROM 上の配置

ROM 上のフォントは

/* necmg.h */
#define NECMG_FONTROM_BASE   0x01400000UL

/* mgfont.c */
#define p_K12x12  0x00000
#define p_A6x12   0x3f000
#define p_K16x16  0x44800
#define p_A8x16   0x83800
#define p_K24x24  0x89800
#define p_A12x24 0x127000
#define p_A8x8    0x89000

において、たとえば JIS X 0201 6x12 フォント全体は p_A6x12 + NECMG_FONTROM_BASEから始まる物理アドレスに存在し、 個々のフォントは JIS X 0201 (0x00 〜 0xff)の場合、

  static inline unsigned char* sfont_pos(unsigned short ch){
      return &(necmg_sfont->p[ch * necmg_sfont->byte_size]);
  }
JIS X 0208 フォント(0x21 0x21 〜 0x7e 0x7e)の場合、
  static inline unsigned char* wfont_pos(unsigned char ch, int ch_2){
    /*
     * ch   第一オクテット。
     * ch_2 第二オクテット(先に走る側; LSB)
     */
    int adr = (int )(ch - 0x21) * 96 + (ch_2 - 0x20);
    return &(necmg_wfont->p[adr * necmg_wfont->byte_size]);
}
で計算されるアドレスからグリフイメージが存在します。それぞれのグリフは LSB が左に、各バイト内は msb が左に、そして上から下に向けて pixel が置かれています。

24x24pixel font (byte_width = 3) の場合、

<-- 左 ---------------- 右 -->
<-- LSB -><--  2 --><-- MSB ->     LSB/MSB: Least/Most significant Byte
<76543210><76543210><76543210>     lsb/msb: Least/Most significant bit
 msb  lsb
<---------- グリフ ---------->

のように配置されており、24x24/8 = 72 バイト ですが グリフ下に空白があり、これを含めて 1 グリフ毎に 80 バイト(byte_size = 80) 使われています。

同じフォーマットながら 12x12 pixel font や 12x24 pixel font は注意を要し、

<-- LSB -><-- MSB-->
<76543210><76543210>
<-- グリフ--><空き->

となっているため unsigned short (sizeof(unsigned short) = 16) で読み出すと語内でグリフが連続していません。

5.2 Linux 上でフォントが使えるようになるタイミング

necmg_mgfont_init()内部で フォントが necmg_fontrom_basevremap() されて以後 初めて ROM フォントを使えるようになりますが、 con_init() によって console を初期化する時点では vremap() がまだ使えません。

vremap() は kernel 内のメモリ管理システムを通じて物理アドレスをカーネル空間にマップしますが、 それはmem_init()によって初期化されていなければなりません。 そして con_init()mem_init() などが出すエラーメッセージをいち早く コンソールに出力しなければならない必要から、mem_init() の後に置くことができません。

そこで vremap() が使えるようになるまでの間 カーネル空間に最初からおかれている clB8x8 をフォントとして使うことができるようにしてあります。 ただ、このフォントは内部構造が上記の ROM フォントとかなり違うことに注意してください( 後述 )。

5.3 struct necmg_fontmetric

PocketLinux 上では 各 ROM Font は struct necmg_fontmetric を通じて管理されています:

/* necmg.h */
struct necmg_fontmetric {
    unsigned char *p;        /* グリフ先頭のアドレス */
    unsigned long size;      /* フォント全体のサイズ */
    int type;                /* 0: ascii, 1: jis x0208, 2: internal ascii */
    int allocated;           /* 0: not allocated, 1: romfont, 2: kmalloced font */
    int pixel_width;
    int pixel_height;
    int byte_width;          /* font 1 scanline あたりバイト数 */
    int byte_size;           /* font 1 文字あたりバイト数 */
    necmg_font_draw draw;
    unsigned char* shift_mask[4];
};

type

アドレスを sfont_pos() で計算するものは 0, wfont_pos で 計算しるものは 1. font_clB8x8_data は例外的に 2 になります。

allocated

その font が使えるかどうか、kfree() できるかどうかを表します。

pixel_width

フォントの幅(pixel 単位)です。

pixel_height

フォントの高さ(pixel 単位)です。

byte_width

フォントの ROM 上での幅(バイト単位)です。

byte_size

フォントの ROM 上での大きさ(バイト単位)です。

draw

このフォントをディスプレイに描くための renderer です。 これを通じて汎用のレンダラ以外の、 そのフォント固有のレンダラを使うことができ、現在 6x12, 8x16 の場合は実際に専用のレンダラを持っています。プロトタイプは

typedef void (*necmg_font_draw)(unsigned short ch, mgfb_t ppos, ...);
と宣言されていて、ディスプレイ上 ppos の位置にフォントchを rendering します。 実際には JIS X 0201 のフォントの場合、
draw( (ch & 0xff) | (ch_attribute << 8) , ppos);
JIS X 0208 のフォントの場合、
draw( (ch & 0x7f) | (ch_attribute << 8) , ppos, (ch_2 & 0x7f));
として使われます。ここで ch は 0x00 〜 0xff のフォント、 ch ch_2 は 0x21 0x21 〜 0x7e 0x7e のフォント、ch_attribute は表示の際の 文字属性を表します。 現在 JIS X 0208 はスクリーン上 JIS X 0201 の倍のサイズをとりますが、 文字の右側の属性を左側と異なるようにすることはできません。

Font rendering の詳細については後述の FONT レンダラの章を参照してください。

shift_mask

ディスプレイ上バイト境界にないところから文字を描く時のための 補助マスクです。事前に計算したものが置かれています。

5.4 /dev/mgfont

デバイスファイル/dev/mgfontは FONT ROM 領域を ユーザースペースから mmap するためにあるデバイスです。

cr--r--r--   1 root     root      58,   0 Mar 22 22:56 mgfont
cr--r--r--   1 root     root      58,   0 Mar 22 22:56 mgfont0
cr--r--r--   1 root     root      58,   1 Mar 22 22:56 mgfont1
cr--r--r--   1 root     root      58,   2 Mar 22 22:56 mgfont2
cr--r--r--   1 root     root      58,   3 Mar 22 22:56 mgfont3
cr--r--r--   1 root     root      58,   4 Mar 22 22:56 mgfont4
cr--r--r--   1 root     root      58,   5 Mar 22 22:56 mgfont5
cr--r--r--   1 root     root      58,   6 Mar 22 22:56 mgfont6
cr--r--r--   1 root     root      58,   7 Mar 22 22:56 mgfont7
cr--r--r--   1 root     root      58,   3 Mar 22 22:56 mgfonts

として用意され、それぞれ

を扱います。mgfonts と mgfont3 が重複していますが、これは JIS X 0208 の 12x12pixel size の内蔵 ROM フォントがフォント領域の先頭に あることによる共有(手抜き)です。

効率的な問題から実用上は mgfonts だけが使われるでしょう。

/* mgl-1.5-0610/mgl.c */
int fn = open("/dev/mgfonts", O_RDONLY);
if(fn < 0){
    perror("open /dev/mgfonts");
    exit(1);
}
font_base = (unsigned char *) mmap((caddr_t)0, 0x200000,
                                  PROT_READ,
                                  MAP_SHARED | MAP_FILE,
                                  fn, 0);

などとして使います。read や seek することもできますが、 FONT イメージをまるごと取得する以外に使い道があるとは思えません。

ioctl

/dev/mgfont* に対する ioctl は二つ定義されています。

MGFONT_GETSIZE

返り値は unsigned long でフォント全体のサイズが返ります。 mgfontsmgfont3 が共有されている都合から、 mgfonts の場合は 全体でなく 12x12 フォントのサイズが返されてしまいます。

MGFONT_GETMETRIC

返り値は sizeof(struct necmg_fontmetric) で、 そのフォントの現在の fontmetric が返ります。 もちろん p, draw, shift_mask はカーネル内のアドレスなので ユーザー空間からアクセスしても何もありません。 p (フォントアドレス) は mmap して取得すればいいとして、draw はカーネル内の関数をユーザー空間から call するのは たかだか 1 文字描くにはあまりにオーバーヘッドが大きいので 用意されていません。 mgfontsmgfont3 の問題はこちらの場合も同じです。

5.5 clB8x8 フォント

カーネル内部の RAM に置かれた clB8x8 フォントは rendering の簡便さを目的として ROM フォントと内部構造が異なります。

clB8x8 は 1 pixel について 2 bit を使い、

<- 左 ------ 右 ->
<- LSB -><- MSB ->
<0011223344556677>
<-- グリフ ------>

LSB を左において上から下に pixel を配置し 0x00 〜 0xff に対するグリフを 持っています。

clB8x8 に関する注意事項

1 pixel が 2 bit に展開されているのはディスプレイが 2bpp だからですが、 カーネルメモリが無駄に消費されているので将来 ROM フォントと同じ構造になるか、 あるいはカーネルから削除されるかもしれません。

また、日本語コンソール移行後は非バイトバウンダリでの font rendering が 発生しますが、clB8x8 は rendering function ( necmg_font_draw_iascii() ) の手抜きから非バイトバウンダリでの 表示ができるようになっていません。 もっともデフォルトフォントが 8x8 になるように(i.e. 80x30) コンソールサイズを切替えた場合は ROM フォントの 8x8 pixel size のものにデフォルトフォントが切り替わり clB8x8 が使われることはありませんから、 この問題がユーザーサイドで露見することはないはずです。

次の章へ , 前の章へ

この章の目次へ, この文書の目次へ

この文書の最初へ , この章の最初へ