入局:應用程式是如何操控lcd顯示器的?
我們知道應用程式的呼叫介面,無非open/read/write…然後通過驅動程式最終作用到硬體裝置上。以字元裝置為例,對於驅動的開發者,實現了應用程式呼叫的驅動層中與之相匹配的drv_open/drv_read/drv_write函式,為應用層序提供了操作實際硬體裝置的通道。那麼,對於lcd驅動程式又是如何?先來了解下兩個非常重要的概念。
lcd控制器的功能是控制驅動訊號,進而驅動lcd。使用者只需要通過讀寫一系列的暫存器,完成配置和顯示驅動。在驅動lcd設計的過程中首要的是配置lcd控制器,而在配置lcd控制器中最重要的一步則是幀緩衝區(frame buffer)的指定。使用者所要顯示的內容皆是從緩衝區中讀出,從而顯示到螢幕上的。幀緩衝區的大小由螢幕的解析度和顯示色彩數決定。驅動幀緩衝的實現是整個驅動開發過程的重點。
幀緩衝(frame buffer)是linux為顯示裝置提供的乙個介面,把視訊記憶體抽象後的一種裝置,允許上層應用程式在圖形模式下直接對顯示緩衝區進行讀寫操作。使用者不必關心物理視訊記憶體的位置、換頁機制等等具體細節,這些都是由frame buffer裝置驅動來完成的。幀緩衝裝置屬於字元裝置。
linux系統frame buffer本質上只是提供了對圖形裝置的硬體抽象,在開發者看來,frame buffer是一塊顯示快取,向顯示快取中寫入特定格式的資料就意味著向螢幕輸出內容。
由於有了frambuffer的抽象,使得應用程式通過定義好的介面就可以訪問硬體。所以應用程式不需要考慮底層的(暫存器級)的操作。應用程式對裝置檔案的訪問一般在/dev目錄,如 /dev/fb*。
核心中的frambuffer在:drivers/video/fbmem.c(fb: frame buffer)
1.我們進入fbmem.c,從入口函式開始分析:
static
int __init fbmem_init
(void
)return0;
}
(1) 建立字元裝置"fb", fb_major=29,主裝置號為29。
(2)建立類,但並沒有建立裝置節點,因為需要註冊了lcd驅動後,才會有裝置節點;
2.應用層對驅動的操作、資料的讀取
2.1 fb_open函式如下:
static
intfb_open
(struct inode *inode,
struct file *file)
return res;
}
(1) registered_fb[fbidx] 這個陣列也是fb_info結構體,其中fbidx等於次裝置號id,顯然這個陣列就是儲存我們各個lcd驅動的資訊;
2.2 fb_read函式如下:
static ssize_t fb_read
(struct file *file,
char __user *buf, size_t count, loff_t *ppos)if(
copy_to_user
(buf, buffer, c)
)*ppos +
= c;
buf +
= c;
cnt +
= c;
count -
= c;
}kfree
(buffer)
;return
(err)
? err : cnt;
}
從.open和.read函式中可以發現,都依賴於fb_info幀緩衝資訊結構體,它從registered_fb[fbidx]陣列中得到,這個陣列儲存我們各個lcd驅動的資訊。由此可見,fbmem.c提供的都是些抽象出來的東西,最終都得依賴registered_fb這個陣列。
3. registered_fb的註冊
int
register_framebuffer
(struct fb_info *fb_info)
這個register_framebuffer()除了註冊fb_info,還建立了裝置節點。
以s3c2410fb.c為例,分析驅動的實現。
1.我們進入drivers/video/s3c2410fb.c,從入口函式開始分析:
int __devinit s3c2410fb_init
(void
)
既然是匯流排裝置驅動模型,那我們關心的是它的probe函式。
2.s3c2410fb_probe
static
int __init s3c2410fb_probe
(struct platform_device *pdev)
mregs =
&mach_info->regs;
irq =
platform_get_irq
(pdev,0)
;if(irq <0)
fbinfo =
framebuffer_alloc
(sizeof
(struct s3c2410fb_info)
,&pdev->dev)
;//1.分配乙個fb_info結構體if(
!fbinfo)
/*2.設定fb_info*/
info = fbinfo->par;
info->fb = fbinfo;
info->dev =
&pdev->dev;..
....
ret =
request_irq
(irq, s3c2410fb_irq, irqf_disabled, pdev->name, info)
;//設定中斷
info->clk =
clk_get
(null
,"lcd");
//獲取時鐘
clk_enable
(info->clk)
;//使能時鐘
ret =
s3c2410fb_map_video_memory
(info)
;//視訊記憶體位址
ret =
s3c2410fb_init_registers
(info)
;//設定暫存器,配置引腳..
....
ret =
register_framebuffer
(fbinfo)
;//4.註冊乙個fb_info結構體
if(ret <0)
....
..return ret;
}
看到這裡驅動的寫法也大致清晰:
1.分配乙個fb_info結構體: framebuffer_alloc();
2.設定fb_info
3.硬體相關的操作(設定中斷,lcd時鐘頻率,視訊記憶體位址, 配置引腳… …)
4.註冊fb_info: register_framebuffer()
附:lcd的顯示過程與時序:
1.顯示從螢幕左上角第一行的第乙個點開始,乙個點乙個點地在lcd上顯示,點與點之間的時間間隔為vclk(畫素時鐘訊號);當顯示到螢幕的最右邊就結束這一行(line),這一行的顯示對應時序圖上的hsync(水平同步訊號)
2. 接下來顯示指標又回到螢幕的左邊從第二行開始顯示,顯示指標針在從第一行的右邊回到第二行的左邊是需要一定的時間的,我們稱之為行切換。
3. 以此類推,顯示指標就這樣一行一行的顯示至矩形的右下角才把一幅影象(幀:frame)顯示完成,這一幀的顯示時間在時序圖上表示為vsync(垂直同步訊號)。
網路驅動程式概述
一 網路驅動程式 使用net device描述裝置,使用套接字描述符sk buff封裝資料。二 裝置的註冊 alloc ethdev分配net device結構和私有的資料區 並初始化乙太網裝置結構 標誌 硬體位址 初始化緩衝區描述符 申請中斷號並註冊中斷處理函式,最後向全域性網路裝置鍊錶新增初始化...
驅動程式開發(一) 概述
很久沒有網了,出了一段時間的差,近來,莫名的就有點鬱悶!也畢業好幾年了,技術還需要提高,開始覺得可以考慮換個方向。以前我是做視音訊開發的。換哪個方向呢?人越多的方向,好像越是沒有前途。想想當初上大學,那可是越多人考的學校,學費越貴啊!可現在的職業呢?越多人幹的事,越是沒有前途了。考慮來考慮去,決定學...
Linux驅動程式框架以及概述
1 字元裝置 char device 2 塊裝置 block device 3 網路裝置 net device 1 對裝置初始化和釋放 2 把資料從核心傳送到硬體和從硬體讀取資料 3 讀取應用程式傳送給裝置檔案的資料和回送應用程式請求的資料 4 檢測和處理裝置出現的錯誤 訪問特定硬體 訪問特定硬體就...