簡體   English   中英

使用framebuffer節點延遲從用戶空間寫入內核空間

[英]delayed write from userspace to kernel space using framebuffer node

我已經實現了一個linux內核驅動程序,它使用延遲IO機制來跟蹤framebuffer節點的變化。

static struct fb_deferred_io fb_defio = {
        .delay          = HZ/2,
        .deferred_io    = fb_dpy_deferred_io,
};

每個人說已注冊的幀緩沖節點是/ dev / graphics / fb1。

訪問此節點的示例應用程序代碼是:

fbfd = open("/dev/graphics/fb1", O_RDWR);
if (!fbfd) {
    printf("error\n");
    exit(0);
}
screensize = 540*960*4;
/* Map the device to memory */
fbp = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                   fbfd, 0);
if ((int)fbp == -1) {
    printf("Error: failed to start framebuffer device to memory.");
}

int grey = 0x1;
    for(cnt = 0; cnt < screensize; cnt++)
            *(fbp + cnt) = grey<<4|grey;

這將用1填充整個fb1節點。

現在的問題是在內核驅動程序上,當我嘗試讀取整個緩沖區時,我發現不同位置的數據不匹配。

內核中的緩沖區映射為:

par->buffer =  dma_alloc_coherent(dev, roundup((dpyw*dpyh*BPP/8), PAGE_SIZE),(dma_addr_t *) &DmaPhysBuf, GFP_KERNEL);
if (!par->buffer) {
        printk(KERN_WARNING "probe: dma_alloc_coherent failed.\n");
        goto err_vfree;
}

最后通過register_framebuffer函數注冊緩沖區。

在讀取源緩沖區時,我發現在隨機位置沒有寫入數據而是反映舊數據。

例如:

在緩沖區位置3964我期待11111111,但我找到了FF00FF00。

在運行相同的應用程序時,灰色值更改為22222222

在緩沖區位置3964我期待22222222,但我找到了11111111

看起來緩沖區中有一些延遲寫入。 是否有任何解決方案,因為部分錯誤的數據我的圖像被破壞。

如果需要更多信息,請告訴我。

注意 :看起來映射緩沖區可以緩存的問題。 它是一個懶惰的寫入,將數據從緩存復制到ram。 需要確保數據被正確復制但仍然不知道...... :-(

“Deferred io”表示幀緩沖存儲器並未真正映射到顯示設備。 相反,它是用戶進程和內核驅動程序之間共享的普通內存區域。 因此,需要“同步”內核才能真正做任何事情:

msync(fbp, screensize, MS_SYNC);

調用fsync(fbfd)也可以。

如果您的驅動程序支持,您也可以嘗試調用ioctl(fbfd, FBIO_WAITFORVSYNC, 0) 該調用將使您的應用程序等待,直到vsync發生並且幀緩沖區數據已明確傳輸到設備。

我有一個類似的問題,我在屏幕上顯示隨機文物。 最初,幀緩沖驅動程序根本沒有使用dma。

我嘗試了使用msync()的建議,這改善了情況(工件發生頻率較低),但它並沒有完全解決問題。

在做了一些研究之后,我得出的結論是我需要使用dma內存,因為它沒有被緩存。 mmap仍然存在問題,因為它將內核內存映射到用戶空間。 但是,我發現內核中已經有一個函數來處理這個問題。

所以,我的解決方案是在我的framebuffer驅動程序中,設置了mmap函數:

static int my_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{
        return dma_mmap_coherent(info->dev, vma, info->screen_base,
                                 info->fix.smem_start, info->fix.smem_len);
}

static struct fb_ops my_fb_ops = {
        ...
        .fb_mmap = my_fb_mmap,
};

然后在探測函數中:

struct fb_info *info;
struct my_fb_par *par;
dma_addr_t dma_addr;
char *buf

info = framebuffer_alloc(sizeof(struct my_fb_par), &my_parent->dev);
...
buf = dma_alloc_coherent(info->dev, MY_FB_SIZE, dma_addr, GFP_KERNEL);
...
info->screen_base = buf;
info->fbops = &my_fb_ops;
info->fix = my_fb_fix;
info->fix.smem_start = dma_addr;
info->fix.smem_len = MY_FB_SIZE;
...
par = info->par
...
par->buffer = buf;

顯然,我已經省略了錯誤檢查和解除,但希望我已經觸及了所有重要的部分。

注意:內核源代碼中的注釋表示dmac_flush_range()僅供私人使用。

最終我找到了解決問題的更好方法。 通過app在mmaped設備節點寫入的數據首先寫入緩存中,稍后通過延遲寫入策略將其寫入RAM。 為了確保正確刷新數據,我們需要在內核中調用flush函數。 我用了

dmac_flush_range((void *)pSrc, (void *)pSrc + bufSize);

完全刷新數據,以便內核接收干凈的數據。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM