トップ 一覧 Farm 検索 ヘルプ RSS ログイン

Diary/2014-4-23の変更点

  • 追加された行はこのように表示されます。
  • 削除された行はこのように表示されます。
!Xillybusのドライバを読む
xillybus_core.c から.まずは,ざっと,どんな感じのものがあるのか見てみる.
これはFPGA内のIPコアのFIFOとデバイスファイルのパイプを作る.
キャラクタデバイスで,構造体は↓な感じ.
 static const struct file_operations xillybus_fops = {
         .owner      = THIS_MODULE,
         .read       = xillybus_read,
         .write      = xillybus_write,
         .open       = xillybus_open,
         .flush      = xillybus_flush,
         .release    = xillybus_release,
         .llseek     = xillybus_llseek,
         .poll       = xillybus_poll,
 };

!初期化関連
::xillybus_init/xillybus_exit
ドライバロード時にやってるのは,
* class_create
* alloc_workqueue
アンロード時には,
* destroy_workqueue
* class_destroy

::xillybus_init_endpoint
 EXPORT_SYMBOL(xillybus_init_endpoint);
でエクスポートされている関数.
xillybus_pcie.cのxilly_probe(←pciドライバの.porbeにマッピングされてる)か,
xillybus_of.cのxilly_drv_probe(platform_driverの.probeにマッピングされてる)から呼ばれる.
デバドラ内部で使うデータの初期化

::xillybus_endpoint_discovery
 EXPORT_SYMBOL(xillybus_endpoint_discovery);
でエクスポートされている関数.
xillybus_pcie.cのxilly_probe(←pciドライバの.porbeにマッピングされてる)か,
xillybus_of.cのxilly_drv_probe(platform_driverの.probeにマッピングされてる)から呼ばれる.
ハードウェアから情報をスキャンしてハンドラを作る.ハンドラの定義は,xillybus.hにある
 struct xilly_idt_handle {
         unsigned char *chandesc;
         unsigned char *idt;
         int entries;
 };
* xilly_setupchannels チャネルのセットアップ.
* xilly_obtain_idt ハードウェアのバージョンチェックなど
* xilly_scan_idt
ハンドラが用意できたら,xillybus_init_chrdevを呼ぶ

::xillybus_init_chrdev
キャラクタデバイスとしての初期化,デバイスファイルを作るのも,ここ.

!アクセス関連
::xillybus_open
モードに応じたチャネルやロックの設定など
* mutex_lock_interruptible
* iowrite32でデバイスにオープンされたことを通知

::xillybus_read
データの読み出し.こんな感じ.
 while(1)
   bytes_to_do = count - bytes_done; 残りの読むべきバイト数をセット
 
   if バッファがemptyでない
     if バッファにたまっている個数(howmany)がbyte_to_doより多い
       bufferdone = 0;
     else
       bufferdone = 1;
     end
   end
 
   if emptyでない
     if (bufops == 0) // バッファが空
       channel->endpoint->ephw->hw_sync_sgl_for_cpuでDMAする(DMA_FROM_DEVICE)
     end
     copy_to_userでバッファのデータをユーザ領域にデータをコピー
     userbuf += howmany
     bytes_done += howmany
     if bufferdoneが0でない then
       channel->endpoint->ephw->hw_sync_sgl_for_cpuでDMAする(DMA_FROM_DEVICE)
       // FPGAにbufferdoneを通知
       iowrite32(1 | (channel->chan_num << 1) | (bufidx << 12),
                 &channel->endpoint->registers[fpga_buf_ctrl_reg]);
     end
   end
 
   // ループの終了判定
   bytes_doneがcount以上かeofに到達 => ループから抜ける
   exhaustedでない => ループ頭に戻る
   bytes_doneが0より大きい
    かつ
   no_time_left か (channel->wr_synchronous && channel->wr_allow_partial) => ループから抜ける
   no_time_leftでない かつ O_NONBLOCKが指定されてた
    bytes_done が 0 より大きい => ループから抜ける
    readyが0でない => desperateへ
    それ以外 => bytes_doneを-EAGAIN(エラー)にしてループから抜ける
 
   !no_time_left または bytes_done > 0
    アライメント調整
 
   if !channel->wr_allow_partial || (no_time_left && (bytes_done == 0))
     do{
       if (wait_event_interruptible(channel->wr_wait, (!channel->wr_sleepy)))
         => interruptedへ
       if (mutex_lock_interruptible(&channel->wr_mutex))
         => interruptedへ
     }while(channel->wr_sleep);
     ループの先頭に戻る
 
     interrupted:
       bytes_doneが0でなければ,return bytes_done
       あるいは エラー
   end
 
   if left_to_sleep > 0 then
      left_to_sleep = wait_event_interruptible_timeout(channel->wr_wait,
                                                       (!channel->wr_sleepy),
                                                       left_to_sleep);
      (!channel->wr_sleepy) => ループの先頭に戻る
      if left_to_sleep < 0 then
        bytes_doneが0でなければ,return bytes_done
        あるいは エラー
      end
   end
 
   desparate:
     no_time_left = 1
 end

::続き
xillybus_write,xillybus_flush,xillybus_release,xillybus_llseek,xillybus_poll
は,また今度.