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
は,また今度.