framebuffer設備驅動的幾個連接關鍵點

framebuffer設備驅動的幾個連接關鍵點

framebuffer的架構

見到的宋寶華老師總結的一個圖表,覺得很清晰,直接移過來了
在這裏插入圖片描述

關鍵點點析

  • 文件driver/video/fbmem.c中的file_operations結構體
  • 文件xxxfb.c,對應於各具體廠商的framebuffer驅動,我這邊看的是fsl的驅動,名字是drivers/video/mxc/mxc_ipuv3_fb.c
  • 在文件xxxxfb.c中的重要結構體爲fb_info,用來連接到文件driver/video/fbmem.c中,連接的函數就是register_framerbufferunregister_framerbuffer。所以在xxxxfb.c中找入口,連接上下層的東西就在這個結構體和兩個函數入口。
  • 應用層的操作入口,例如讀、寫、控制等,在文件xxxxfb.c中實現,通過結構體fb_infofbops(類型爲struct fb_ops)成員來連接。所以驅動最主要的是要實現結構體struct fb_ops成員的填充。以下根據實例代碼,描述連接。

實例代碼

文件drivers/video/mxc/mxc_ipuv3_fb.c

static struct fb_ops mxcfb_ops = {   /* 註冊關鍵的操作函數 11111111111 */
	.owner = THIS_MODULE,
	.fb_set_par = mxcfb_set_par,
	.fb_check_var = mxcfb_check_var,
	.fb_setcolreg = mxcfb_setcolreg,
	.fb_pan_display = mxcfb_pan_display,
	.fb_ioctl = mxcfb_ioctl,
	.fb_mmap = mxcfb_mmap,
	.fb_fillrect = cfb_fillrect,
	.fb_copyarea = cfb_copyarea,
	.fb_imageblit = cfb_imageblit,
	.fb_blank = mxcfb_blank,
};

......
static struct fb_info *mxcfb_init_fbinfo(struct device *dev, struct fb_ops *ops)   /* 333333333  */
{
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;

	/*
	 * Allocate sufficient memory for the fb structure
	 */
	fbi = framebuffer_alloc(sizeof(struct mxcfb_info), dev);
	if (!fbi)
		return NULL;

	mxcfbi = (struct mxcfb_info *)fbi->par;

	fbi->var.activate = FB_ACTIVATE_NOW;

	fbi->fbops = ops;                   /*************將fb_ops 註冊到 fb_info 中****************/
	fbi->flags = FBINFO_FLAG_DEFAULT;
	fbi->pseudo_palette = mxcfbi->pseudo_palette;

	/*
	 * Allocate colormap
	 */
	fb_alloc_cmap(&fbi->cmap, 16, 0);

	return fbi;
}
......

static int mxcfb_probe(struct platform_device *pdev)
{
	......
	struct fb_info *fbi;	
	......

	fbi = mxcfb_init_fbinfo(&pdev->dev, &mxcfb_ops);   /* 註冊11111111111,詳見333333333 。   2222222222222 */
	......
	
	mxcfb_register(fbi);  /* 最終調用 register_framebuffer(fbi); 進行註冊,將fb_info 註冊到驅動架構中 */
                                     /* 繼續往下個文件看 */
	......
}

文件driver/video/fbmem.c

int
register_framebuffer(struct fb_info *fb_info)
{
	int ret;

	mutex_lock(&registration_lock);
	ret = do_register_framebuffer(fb_info);   /* 所以實際在這裏面*/
	mutex_unlock(&registration_lock);

	return ret;
}

static int do_register_framebuffer(struct fb_info *fb_info)
{
	int i;
	struct fb_event event;
	struct fb_videomode mode;

	if (fb_check_foreignness(fb_info))
		return -ENOSYS;

	do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
					 fb_is_primary_device(fb_info));

	if (num_registered_fb == FB_MAX)
		return -ENXIO;

	num_registered_fb++;
	for (i = 0 ; i < FB_MAX; i++)  /* 找到第一個可用的fb */
		if (!registered_fb[i])
			break;
	fb_info->node = i;
	atomic_set(&fb_info->count, 1);  /* 設置原子操作數爲 1 */
	mutex_init(&fb_info->lock);      /* 初始化互斥體 lock       Lock for open/release/ioctl funcs **/
	mutex_init(&fb_info->mm_lock);   /* 初始化互斥體 mm_lock Lock for fb_mmap and smem_* fields */

	fb_info->dev = device_create(fb_class, fb_info->device,    /* 在/dev/ 目錄下創建一個fb* 的設備結點 */
				     MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
	if (IS_ERR(fb_info->dev)) {
		/* Not fatal */
		printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
		fb_info->dev = NULL;
	} else
		fb_init_device(fb_info);  /* 裏面構建所有的屬性文件,賦予用戶空間操作 */

	if (fb_info->pixmap.addr == NULL) {
		fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
		if (fb_info->pixmap.addr) {
			fb_info->pixmap.size = FBPIXMAPSIZE;
			fb_info->pixmap.buf_align = 1;
			fb_info->pixmap.scan_align = 1;
			fb_info->pixmap.access_align = 32;
			fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
		}
	}	
	fb_info->pixmap.offset = 0;

	if (!fb_info->pixmap.blit_x)
		fb_info->pixmap.blit_x = ~(u32)0;

	if (!fb_info->pixmap.blit_y)
		fb_info->pixmap.blit_y = ~(u32)0;

	if (!fb_info->modelist.prev || !fb_info->modelist.next)
		INIT_LIST_HEAD(&fb_info->modelist);

	if (fb_info->skip_vt_switch)
		pm_vt_switch_required(fb_info->dev, false);
	else
		pm_vt_switch_required(fb_info->dev, true);

	fb_var_to_videomode(&mode, &fb_info->var);
	fb_add_videomode(&mode, &fb_info->modelist);
	registered_fb[i] = fb_info;   /**************** 連接關鍵點,下面的圍繞它來找出 fb_info中的操作 和 
	                                  file_operation 中的操作的連接關係 ***********/

	event.info = fb_info;
	if (!lock_fb_info(fb_info))
		return -ENODEV;
	console_lock();
	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
	console_unlock();
	unlock_fb_info(fb_info);
	return 0;
}

extern struct fb_info *registered_fb[FB_MAX];   /********** 就是一個數組 (文件include/linux/fb.h中)**********/

static const struct file_operations fb_fops = {   /********** 注意,這是file_operations  相關函數的註冊 */
	.owner =	THIS_MODULE,
	.read =		fb_read,			/* 下面以它爲契機,去1111111111 */
	.write =	fb_write,
	.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = fb_compat_ioctl,
#endif
	.mmap =		fb_mmap,
	.open =		fb_open,
	.release =	fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA
	.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	.fsync =	fb_deferred_io_fsync,
#endif
	.llseek =	default_llseek,
};

static ssize_t
fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)  /* 1111111111 */
{
	unsigned long p = *ppos;
	struct fb_info *info = file_fb_info(file);   /* 連接點,繼續往裏面看,去 222222222222 */

	......

	if (info->fbops->fb_read)  /* 之前在文件 mxc_ipuv3_fb.c 中註冊的 fb_read */
		return info->fbops->fb_read(info, buf, count, ppos);
	
	......
}

static struct fb_info *file_fb_info(struct file *file)  /* 222222222222 */
{
	struct inode *inode = file_inode(file);
	int fbidx = iminor(inode);
	struct fb_info *info = registered_fb[fbidx];   /***** 熟悉的背影:registered_fb,
	                                    通過它將之前註冊的fb_info 找到! */

	if (info != file->private_data)
		info = NULL;
	return info;
}

重要結構體

struct fb_info

struct fb_info {
	......
	struct fb_var_screeninfo var;	/* Current var */
	struct fb_fix_screeninfo fix;	/* Current fix */
	struct fb_monspecs monspecs;	/* Current Monitor specs */
	struct work_struct queue;	/* Framebuffer event queue */
	struct fb_pixmap pixmap;	/* Image hardware mapper */
	struct fb_pixmap sprite;	/* Cursor hardware mapper */
	struct fb_cmap cmap;		/* Current cmap */
	struct list_head modelist;      /* mode list */
	struct fb_videomode *mode;	/* current mode */

#ifdef CONFIG_FB_BACKLIGHT
	......
#endif

	......
	struct fb_ops *fbops;     /************* 連接點 *********************/
	struct device *device;		/* This is the parent */
	struct device *dev;		/* This is this fb device */
	int class_flag;                    /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
	struct fb_tile_ops *tileops;    /* Tile Blitting */
#endif
	char __iomem *screen_base;	/* Virtual address */
	unsigned long screen_size;	/* Amount of ioremapped VRAM or 0 */ 
	......
};

struct fb_ops

struct fb_ops {
	/* open/release and usage marking */
	struct module *owner;
	int (*fb_open)(struct fb_info *info, int user);
	int (*fb_release)(struct fb_info *info, int user);

	/* For framebuffers with strange non linear layouts or that do not
	 * work with normal memory mapped access
	 */
	ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
			   size_t count, loff_t *ppos);
	ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
			    size_t count, loff_t *ppos);

	/* checks var and eventually tweaks it to something supported,
	 * DO NOT MODIFY PAR */
	int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);

	/* set the video mode according to info->var */
	int (*fb_set_par)(struct fb_info *info);

	/* set color register */
	int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
			    unsigned blue, unsigned transp, struct fb_info *info);

	/* set color registers in batch */
	int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);

	/* blank display */
	int (*fb_blank)(int blank, struct fb_info *info);

	/* pan display */
	int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
	......
	/* Draws cursor */
	int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);

	/* Rotates the display */
	void (*fb_rotate)(struct fb_info *info, int angle);

	/* wait for blit idle, optional */
	int (*fb_sync)(struct fb_info *info);

	/* perform fb specific ioctl (optional) */
	int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
			unsigned long arg);
	......
	/* perform fb specific mmap */
	int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);

	......
};

總結

一個簡單的驅動,重要的是摸清脈絡,搞清調用關係,這樣有問題或者想靈活操作(例如更改等)可以找準下手點。本文主要目的是弄清軟件流程,至於裏面的具體實施跟具體的芯片有關,例如本文提到的例子,用的fsl的片子,而這裏面糅合了ipu來進行framebuffer來處理,它的ipu操作並沒有在這裏進行分析,做顯示的東西比較多,對他的ipu也有一定的瞭解,有時間會另外寫出來。本文留做快速回憶或者稍微幫大家理理,希望有用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章