*メモ [#p6ca7065]
USL-5Pのボタンの割り込みメモ
-ユーザプロセスへどうやってボタン割り込みを通知するか?~すこし考えてみる。~
--案1:割り込みハンドラでsignalを生成してユーザプロセスにボタン押下イベントを通知する。~
--案2:ユーザプロセスはselectで待ちうけ。割り込みハンドラは、その待ち受け解除する。~
結果的にボタンの押下イベントがユーザプロセスへ伝わる。~
-前者は、直感的で解りやすい。後者は、扱いやすい。?
*まず、前者の実装を行ってみる。 [#l731e969]

-カーネル内
--割り込み番号13までサポート。さらに、ボタン割り込みを登録。
#pre{{
void __init init_julian_IRQ(void)
{
	int i;

	for (i=5; i<&color(red){14};; i++)
		make_julian_irq(i);
}
}}
--割り込みハンドラの登録。(2つの割り込みでハンドラを共有)
#pre{{
	if (request_irq(IRQ_POWER, &color(red){sw_interrupt};, 0, "SHUTDOWNSWITCH", NULL)) {
		printk(KERN_ERR "Unable to get IRQ 11.\n");
		return 1;
	}
	if (request_irq(IRQ_BUTTON, &color(red){sw_interrupt};, 0, "USL-5P BUTTON", NULL)) {
		printk(KERN_ERR "Unable to get IRQ 12.\n");
		return 1;
	}
}}

--割り込みハンドラ本体
#pre{{
static irqreturn_t &color(red){sw_interrupt};(int irq, void *dev_id, struct pt_regs *regs)
{
    landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));  // ボタンの読み出し
    disable_irq(IRQ_BUTTON);                         // 割り込み禁止
    disable_irq(IRQ_POWER);                          // 割り込み禁止
    ctrl_outb(0x00, PA_PWRINT_CLR);                  // 割り込み線の解除?

    if(landisk_btnctrlpid != 0){                     // ユーザプロセスのPIDチェック
      kill_proc(landisk_btnctrlpid, SIGUSR1, 1);     // ユーザプロセスへシグナル送信
      landisk_btnctrlpid = 0;            // ハンドシェイク終了   
    }

    return IRQ_HANDLED;
}
}}
--ユーザプロセスのPID受け渡し部分(ioctlルーチン)。~
#pre{{
  case GIODRV_IOCSGIO_BTNPID: 
    landisk_btnctrlpid  = data;         // data: ユーザプロセスのPID
    landisk_btn = 0;
    if(irq_desc[IRQ_BUTTON].depth){     
      enable_irq(IRQ_BUTTON);           // ボタン割り込み許可
    }
    if(irq_desc[IRQ_POWER].depth){
      enable_irq(IRQ_POWER);            // ボタン割り込み許可
    }
    break;
}}
-シグナルを受け取るユーザプロセス~
#pre{{
int main(int argc, char *argv[])
{
  …省略…

  pid = getpid();
  if(signal(SIGUSR1, catch_SIGUSR1) == SIG_ERR){ // シグナルハンドラの登録
    printf("failed to set signal handler.\n");
    exit(0);
  }

  while(1){
    catch_signal = 0;                        // ハンドシェイク開始
    ioctl(fd, GIODRV_IOCSGIO_BTNPID, &pid);  // 自身のPIDをセットする。
         // (ボタン割り込み発生時、カーネルは本PIDへシグナルを発信する。)
                                       
    while(catch_signal == 0){                // シグナル受信待ちループ
      sleep(10);   // シグナル受信時、sleepは即刻解除され、catch_SIGUSR1へ制御が移る。
    }
    // 以下シグナル(ボタン割り込み)を受け取った場合のみ実行される。
 …省略…

  }
}

static void catch_SIGUSR1(int sig)   // シグナルハンドラ
{
  catch_signal = 1;
} 
}}
-うまく動作しているみたい。
*後者の実装 [#e2b1deee]
前者の実装で満足してしまったので、今後の課題とする。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS