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