メモ Edit

USL-5Pのボタンの割り込みメモ

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

まず、前者の実装を行ってみる。 Edit

  • カーネル内
    • 割り込み番号13までサポート。さらに、ボタン割り込みを登録。
      void __init init_julian_IRQ(void)
      {
      	int i;
      
      	for (i=5; i<14; i++)
      		make_julian_irq(i);
      }
      
    • 割り込みハンドラの登録。(2つの割り込みでハンドラを共有)
      	if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
      		printk(KERN_ERR "Unable to get IRQ 11.\n");
      		return 1;
      	}
      	if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
      		printk(KERN_ERR "Unable to get IRQ 12.\n");
      		return 1;
      	}
      
  • 割り込みハンドラ本体
    static irqreturn_t 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ルーチン)。
      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;
    
  • シグナルを受け取るユーザプロセス
    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;
    } 
    
  • うまく動作しているみたい。

後者の実装 Edit

前者の実装で満足してしまったので、今後の課題とする。


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2006-06-13 (火) 20:02:26 (6526d)