2009年7月6日月曜日

set_video

今回は「set_video」を見ていきます。

arch/x86/boot/video.c
=====
void set_video(void)
{
  /* ここにはSVGAモードが入る(header.Sより) */
  u16 mode = boot_params.hdr.vid_mode;

  /* ヒープ位置をリセット */
  RESET_HEAP();
  /* ビデオ関連のパラメータセット(後述) */
  store_mode_params();
  /* set_mode_paramsで設定したパラメータを別変数に退避 */
  save_screen();
  /* ビデオカードのプローブ */
  probe_cards(0);

  /*〜省略〜 */

  /* EDIDを読み込みブートパラメータ構造体にセット */
  vesa_store_edid();
  /* ビデオ関連のパラメータセット#2回目 */
  store_mode_params();

  /* 必要ならsave_screen()で退避させた情報を使ってスクリーン情報を復元する */
  if (do_restore)
  restore_screen();
 }
=====

まずboot_params.hdr.vid_modeの値をローカル変数に代入して、このローカル変数を関数内で参照していますが
この値はheader.Sにて定義されています。


そしてその後は各関数をコールしてビデオ関連の情報をブートパラメータにセットします。
まずは「store_mode_params」。

=====
static void store_mode_params(void)
{
  /*〜省略〜*/

  /* 16色テキストモード(80*25)に設定してカーソル位置を */
  /* boot_params.screen_info.orig_x/y に格納 */
  store_cursor_position();
  /* ビデオモードを取得して、                             */
  /* boot_params.screen_info.orig_video_modeと */
  /* boot_params.screen_info.orig_video_page に格納 */
  store_video_mode();

  /* ビデオモードに合わせてビデオセグメントをセット */
  if (boot_params.screen_info.orig_video_mode == 0x07) {
   /* 〜省略〜 */
 }

  /* フォントサイズをセット */
 set_fs(0);
 font_size = rdfs16(0x485); /* Font size, BIOS area */
 boot_params.screen_info.orig_video_points = font_size;

  /* 〜省略〜*/

 /* ビデオの縦横をセット */
  boot_params.screen_info.orig_video_cols  = x;
 boot_params.screen_info.orig_video_lines = y;
}
======
実際にBIOS関数を使ってビデオモードを取得しているのは「store_vide_mode」関数になります。レジスタに値をセットしてソフトウェア割り込みを起こすいつもの手順なので詳細はスキップします。次にビデオカードをプローブする「probe_cards」です。

arch/x86/boot/video-mode.c
======
void probe_cards(int unsafe)
{
  /*〜省略〜 */

  /* .videocardsセクションの情報をチェック */
  for (card = video_cards; card < video_cards_end; card++) {
   /* unsafeの値がパラメータと一致したらプローブ関数をコールする */
   if (card->unsafe == unsafe) {
   if (card->probe)
     card->nmodes = card->probe();
   else
    card->nmodes = 0;
   }
  }
}
======
card_info構造体にプローブ時に呼び出すためのコールバック関数が指定されていればそのプローブ関数をコールして戻り値をnmodesメンバに格納します。プローブ対象の領域はvideocardsセクションで指定された領域になります。

ビデオカードの情報をセットした次は接続しているディスプレイの情報をとりにいきます。

arch/x86/boot/video-vesa.c
======
void vesa_store_edid(void)
{
  /* 〜省略〜 */

  /* EDIDに未対応のバージョンなら何もしない */
  if (vginfo.version < 0x0200)
   return; /* EDID requires VBE 2.0+ */
 
  ax = 0x4f15; /* VBE DDC */
  bx = 0x0000; /* Report DDC capabilities */
  cx = 0; /* Controller 0 */
  di = 0; /* ES:DI must be 0 by spec */

  /*  DDCが使えるか問い合わせ */
  asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es"
    : "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di)
    : : "esi", "edx");

  /* 〜省略〜 */

  /* EDIDを読み込んで、boot_params.edid_infoにセット */
  ax = 0x4f15; /* VBE DDC */
  bx = 0x0001; /* Read EDID */
  cx = 0; /* Controller 0 */
  dx = 0; /* EDID block number */
  di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */
  asm(INT10
    : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info),
      "+c" (cx), "+D" (di)
    : : "esi");
}

======
EDIDとは接続しているディスプレイのIDのことです。このIDをもとに解像度を設定します。DDCとはDisplay Data Channelのことでディスプレイの情報を通知する方式です。ここではEDIDをとってきてブートパラメータにセットしているだけです。

0 件のコメント:

コメントを投稿