- 追加された行はこのように表示されます。
- 削除された行は
このように表示されます。
!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
は,また今度.