標籤:
分析內種LCD驅動程式架構
LCD在fbmem.c檔案中
1.找到init.函數
static int __initfbmem_init(void)
{
做的工作: (1).if (register_chrdev(FB_MAJOR,"fb",&fb_fops))註冊字元處理函數結構體,以及產生裝置號,
(2)fb_class = class_create(THIS_MODULE, "graphics");產生一個類
}
2.開啟註冊裝置中的字元函數結構體fb_fops
static const struct file_operations fb_fops = {
.owner =THIS_MODULE,
.read =fb_read,
.write =fb_write,
.ioctl =fb_ioctl,
.mmap =fb_mmap,
.open =fb_open,
.release =fb_release,
};
APP層如果要開啟這個裝置,就會執行經過系統調用執行fb_open函數
3.分析這個函數
static int fb_open(struct inode *inode, struct file *file)
{
int fbidx = iminor(inode);產生一個次裝置號
struct fb_info *info;定義一個fb_info結構體
if (!(info = registered_fb[fbidx]))把registered_fb[]結構體數組中以這個裝置的次裝置號為索引,把數組中的值賦值給info
}
4.如果應用程式要對這個驅動進行讀寫操作,就會調用read函數
static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
那麼讀函數主要做的工作:
int fbidx = iminor(inode);獲得裝置的次裝置號
struct fb_info *info = registered_fb[fbidx];在fb_info結構體中以此裝置號為索引找到一個成員賦值給info變數。
if (info->fbops->fb_read)如果字元結構體函數定義fb_read,則執行相應處理
return info->fbops->fb_read(info, buf, count, ppos);
total_size = info->screen_size; 虛擬屏的大小
buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count,分配頁大小的緩衝區
src = (u32 __iomem *) (info->screen_base + p);//顯存基地址,作為源地址
dst = buffer;把分配的緩衝區作為目的地址
*dst++ = fb_readl(src++);把源地址中的資料拷貝到目的地址中
if (copy_to_user(buf, buffer, c))把資料傳遞到應用程式
kfree(buffer);釋放緩衝區
}
不管是讀還是寫都用到了registered_fb[];
5.那麼這個結構體數組是怎麼賦值的呢registered_fb[];
在這個函數中有對這個結構體進行賦值
int register_framebuffer(struct fb_info *fb_info)
{
分析這個函數
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), "fb%d", i);在fb_class類下面建立一個類的裝置,
fb_init_device(fb_info);初始化這個裝置
......對fb_info進行初始化操作
registered_fb[i] = fb_info;把這個傳進來的變數存入數組中,那麼是由誰調用這個函數,並傳進參數的呢
可以發現有很多不同廠家的觸控螢幕.c函數都會調用這個函數,這說明這個函數是抽象出來的,大家都在用它,那麼根據什麼來區別他們呢,那就根據registered_fb數組中的成員,
}
6.比如開啟s3c2410fb.c這個函數,
找到init函數
int __devinit s3c2410fb_init(void)
{
return platform_driver_register(&s3c2410fb_driver);
}
進入到int platform_driver_register(struct platform_driver *drv)裡面
{
drv->driver.bus = &platform_bus_type;
....
return driver_register(&drv->driver);
}
}
進入int driver_register(struct device_driver * drv)函數裡面
{....
return bus_add_driver(drv);
int bus_add_driver(struct device_driver *drv)
error = driver_attach(drv);
bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
driver_probe_device(drv, dev);
if (drv->bus->match && !drv->bus->match(dev, drv))
return ret;如果裝置和驅動的名字匹配,那麼就會調用probe函數,也就是會調用
.probe= s3c2410fb_probe,這個函數
7.分析這個函數static int __init s3c2410fb_probe(struct platform_device *pdev)
{
主要工作:struct fb_info *fbinfo;定義一個fb_info結構體指標變數
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);為這個結構體指標變數分配大小
....初始化這個結構體
ret = register_framebuffer(fbinfo);註冊這個結構體,就把這個結構體註冊到核心中,也就是存在registered_fb數組中去,
}
總結:整個LCD驅動架構就是裝置和驅動分離
驅動是對所有的LCD抽出來的共性
裝置是根據不同廠家的LCD來進註冊,如果裝置的名字和驅動的名字相同,那麼就可以調用probe函數對著裝置進行註冊;從而達到了裝置和驅動分離的目的。
LCD核心內建驅動分析