Linux-FrameBuffer fb_info结构体解析申请以及注册

fb_info 结构体(fb.h(include/linux))

struct fb_info {
	atomic_t count;
	int node;
	int flags;
	struct mutex lock;		/* Lock for open/release/ioctl funcs */
	struct mutex mm_lock;		/* Lock for fb_mmap and smem_* fields */
	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
	/* assigned backlight device */
	/* set before framebuffer registration, 
	   remove after unregister */
	struct backlight_device *bl_dev;

	/* Backlight level curve */
	struct mutex bl_curve_mutex;	
	u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
	struct delayed_work deferred_work;
	struct fb_deferred_io *fbdefio;
#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
	union {
		char __iomem *screen_base;	/* Virtual address */
		char *screen_buffer;
	};
	unsigned long screen_size;	/* Amount of ioremapped VRAM or 0 */ 
	void *pseudo_palette;		/* Fake palette of 16 colors */ 
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1
	u32 state;			/* Hardware state i.e suspend */
	void *fbcon_par;                /* fbcon use-only private area */
	/* From here on everything is device dependent */
	void *par;
	/* we need the PCI or similar aperture base/size not
	   smem_start/size as smem_start may just be an object
	   allocated inside the aperture so may not actually overlap */
	struct apertures_struct {
		unsigned int count;
		struct aperture {
			resource_size_t base;
			resource_size_t size;
		} ranges[0];
	} *apertures;

	bool skip_vt_switch; /* no VT switch on suspend/resume required */
};
  1. count:fb_info的引用计数,fb_open 时使其加1,release时使其减1,为0时,destroy
  2. node:全局变量registered_fb中的索引值,注册的时候分配,通过node可以索引fb_info
  3. flags:一些标志位,有关于硬件加速的,大小端,fb的内存位置(设备或者内存),具体硬件加速的方法,表明哪个使用了硬件加速
#define FBINFO_MODULE		0x0001	/* Low-level driver is a module */
#define FBINFO_HWACCEL_DISABLED	0x0002
   /* When FBINFO_HWACCEL_DISABLED is set:
    *  Hardware acceleration is turned off.  Software implementations
    *  of required functions (copyarea(), fillrect(), and imageblit())
    *  takes over; acceleration engine should be in a quiescent state */

/* hints */
#define FBINFO_VIRTFB		0x0004 /* FB is System RAM, not device. */
#define FBINFO_PARTIAL_PAN_OK	0x0040 /* otw use pan only for double-buffering */
#define FBINFO_READS_FAST	0x0080 /* soft-copy faster than rendering */

/* hardware supported ops */
/*  semantics: when a bit is set, it indicates that the operation is
*   accelerated by hardware.
*  required functions will still work even if the bit is not set.
*  optional functions may not even exist if the flag bit is not set.
*/
#define FBINFO_HWACCEL_NONE		0x0000
#define FBINFO_HWACCEL_COPYAREA		0x0100 /* required */
#define FBINFO_HWACCEL_FILLRECT		0x0200 /* required */
#define FBINFO_HWACCEL_IMAGEBLIT	0x0400 /* required */
#define FBINFO_HWACCEL_ROTATE		0x0800 /* optional */
#define FBINFO_HWACCEL_XPAN		0x1000 /* optional */
#define FBINFO_HWACCEL_YPAN		0x2000 /* optional */
#define FBINFO_HWACCEL_YWRAP		0x4000 /* optional */

#define FBINFO_MISC_USEREVENT          0x10000 /* event request
   					  from userspace */
#define FBINFO_MISC_TILEBLITTING       0x20000 /* use tile blitting */

/* A driver may set this flag to indicate that it does want a set_par to be
* called every time when fbcon_switch is executed. The advantage is that with
* this flag set you can really be sure that set_par is always called before
* any of the functions dependent on the correct hardware state or altering
* that state, even if you are using some broken X releases. The disadvantage
* is that it introduces unwanted delays to every console switch if set_par
* is slow. It is a good idea to try this flag in the drivers initialization
* code whenever there is a bug report related to switching between X and the
* framebuffer console.
*/
#define FBINFO_MISC_ALWAYS_SETPAR   0x40000

/* where the fb is a firmware driver, and can be replaced with a proper one */
#define FBINFO_MISC_FIRMWARE        0x80000
/*
* Host and GPU endianness differ.
*/
#define FBINFO_FOREIGN_ENDIAN	0x100000
/*
* Big endian math. This is the same flags as above, but with different
* meaning, it is set by the fb subsystem depending FOREIGN_ENDIAN flag
* and host endianness. Drivers should not use this flag.
*/
#define FBINFO_BE_MATH  0x100000

/* report to the VT layer that this fb driver can accept forced console
  output like oopses */
#define FBINFO_CAN_FORCE_OUTPUT     0x200000
  1. var:变量,描述的是具体屏的一些参数,包括可见的分辨率,Bpp(bits_per_pixel),还有具体的时钟信号,包括bp,fp,vsync,hsync等,可以通过应用层设置也可以驱动层配置,相关设置时序的工具有fbset,还有相关的一些调色板配置Linux-FrameBuffer fb_info结构体解析申请以及注册_第1张图片
  2. fix:描述的是不可变量,驱动中控制参数,不能在用户层更改。包括显存起始位置(一般是显示控制器DMA起始地址-物理地址,smem_start),framebuffer的长度(smem_len)
  3. monspecs:描述的是显示器的一些参数,时序,生产日期等,一般这种信息描述在显示器中的EDID中,通过解析EDID来填充此参数
  4. queue:事件队列,不过分析多个驱动,并没有发现使用该字段的,等遇到再做更新
  5. pixmap,sprite(光标)都是像素图,注册framebuffer的时候会默认申请,未知干什么用的
  6. cmap:设备独立的 colormap 信息,可以通过 ioctl 的 FBIOGETCMAP 和 FBIOPUTCMAP 命令设置 colormap;
  7. modelist:将var参数转化成video mode,然后存入这个链表
  8. mode:一些时序,刷新率扫描方式(vmode)(隔行,逐行),极性(sync)
  9. 关于背光CONFIG_FB_BACKLIGHT,有关于背光曲线以及背光设备注册,需要注意的是需要在注册framebuffer之前就对其初始化
  10. CONFIG_FB_DEFERRED_IO,延迟IO,使用缺页中断的原理操作,减少FBIOPAN_DISPLAY带来的系统调用开支。原理
  11. fbops:提供具体的fb操作函数,主要是通过fbmem.c中提供的文件操作函数,间接调用fb_ops,主要的操作有fb_check_var,fb_pan_display,fb_mmap,等,以下三个函数提供了绘图的操作,可以使用系统中的绘图函数,也可以重写硬件加速的绘图函数
/* Draws a rectangle */
   void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
   /* Copy data from area to another */
   void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
   /* Draws a image to the display */
   void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
  1. device:fb_info的设备父节点,对应即sys/device/xxx/fb_info
  2. dev:设备指针,注册framebuffer时创建
  3. pseudo_palette:伪调色板
  4. state:硬件状态,在fbmem中会设置成suspend以及resume
#define FBINFO_STATE_RUNNING	0
#define FBINFO_STATE_SUSPENDED	1

19.skip_vt_switch:关于VT switch,是与console切换以及PM相关的,具体

framebuffer的申请

struct fb_info * framebuffer_alloc(size_t size, struct device *dev)

struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
{
#define BYTES_PER_LONG (BITS_PER_LONG/8)
#define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG))
   int fb_info_size = sizeof(struct fb_info);
   struct fb_info *info;
   char *p;

   if (size)
   	fb_info_size += PADDING;

   p = kzalloc(fb_info_size + size, GFP_KERNEL);

   if (!p)
   	return NULL;

   info = (struct fb_info *) p;

   if (size)
   	info->par = p + fb_info_size;

   info->device = dev;

#ifdef CONFIG_FB_BACKLIGHT
   mutex_init(&info->bl_curve_mutex);
#endif

   return info;
#undef PADDING
#undef BYTES_PER_LONG
}
EXPORT_SYMBOL(framebuffer_alloc);
  • 位置
    fbsysfs.c video\fbdev\core
  • 功能
    申请fb_info,初始化其内部的少许成员(device,par,bl_curve_mutex(CONFIG_FB_BACKLIGHT))
  • 传入参数
    size:除了fb_info的结构体申请之外,多申请的字节数,将多申请的首地址赋值给par,假如为0,则不用顾及par,为NULL,也不会涉及到字节对齐
    device:赋值fb_info中device,作为fb_info的父节点存在,表现是sysfs中的子目录与父目录关系

framebuffer注册

int register_framebuffer(struct fb_info *fb_info)

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

	if (fb_check_foreignness(fb_info))
		return -ENOSYS;

	ret = do_remove_conflicting_framebuffers(fb_info->apertures,
						 fb_info->fix.id,
						 fb_is_primary_device(fb_info));
	if (ret)
		return ret;

	if (num_registered_fb == FB_MAX)
		return -ENXIO;

	num_registered_fb++;
	for (i = 0 ; i < FB_MAX; i++)
		if (!registered_fb[i])
			break;
	fb_info->node = i;
	atomic_set(&fb_info->count, 1);
	mutex_init(&fb_info->lock);
	mutex_init(&fb_info->mm_lock);

	fb_info->dev = device_create(fb_class, fb_info->device,
				     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;

	event.info = fb_info;
	if (!lockless_register_fb)
		console_lock();
	if (!lock_fb_info(fb_info)) {
		if (!lockless_register_fb)
			console_unlock();
		return -ENODEV;
	}

	fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
	unlock_fb_info(fb_info);
	if (!lockless_register_fb)
		console_unlock();
	return 0;
}
  • 作用
    注册framebuffer到framebuffer框架下的全局变量registered_fb

  • framebuffer的框架(框架图抄来的)
    Linux-FrameBuffer fb_info结构体解析申请以及注册_第2张图片在framebuffer框架中(fbmem.c),完成了对字符设备的注册,申请了Major=29(FB_MAJOR),此设备号从0开始,总共256(实际上只支持32个#define FB_MAX 32 /* sufficient for now */)的设备数,并提供了f_ops,
    ret = register_chrdev(FB_MAJOR, "fb", &fb_fops);

static const struct file_operations fb_fops = {
	.owner =	THIS_MODULE,
	.read =		fb_read,
	.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,
};
  • 注册成功的结果
    1.添加到全局变量registered_fb数组中,其索引号赋值给fb_info中的node 成员变量
    2.索引号作为次设备号,创建/dev/fb%d的设备节点,%d 是次设备号
    fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
    3.在其/sys/xxx/下创建一系列的属性文件(由fb_init_device完成),其中xxx包含父节点的目录
static struct device_attribute device_attrs[] = {
	__ATTR(bits_per_pixel, S_IRUGO|S_IWUSR, show_bpp, store_bpp),
	__ATTR(blank, S_IRUGO|S_IWUSR, show_blank, store_blank),
	__ATTR(console, S_IRUGO|S_IWUSR, show_console, store_console),
	__ATTR(cursor, S_IRUGO|S_IWUSR, show_cursor, store_cursor),
	__ATTR(mode, S_IRUGO|S_IWUSR, show_mode, store_mode),
	__ATTR(modes, S_IRUGO|S_IWUSR, show_modes, store_modes),
	__ATTR(pan, S_IRUGO|S_IWUSR, show_pan, store_pan),
	__ATTR(virtual_size, S_IRUGO|S_IWUSR, show_virtual, store_virtual),
	__ATTR(name, S_IRUGO, show_name, NULL),
	__ATTR(stride, S_IRUGO, show_stride, NULL),
	__ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
	__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
#ifdef CONFIG_FB_BACKLIGHT
	__ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
#endif
};

4.初始化pixmap的成员变量,具体要干什么未知,后面更新
5.将var的中的屏的参数转换成fb_videomode,将其mode挂载在modelist链表中去,当然首次会初始化modelist
INIT_LIST_HEAD(&fb_info->modelist);
6.skip_vt_switch,主要是console在suspend的时候切换console,调用
pm_vt_switch_required(fb_info->dev, false);完成。设置为1,则不进行切换,当然也要使能对应的CONFIG,CONFIG_VT_CONSOLE_SLEEP
7.通过通知链,将FB_EVENT_FB_REGISTERED的事件发送出去,通知链的原理是建立一个链表,向其注册回调,通过xxx_notifier_call_chain,将事件发送出去,这个通知链会经常用到,通知一些包括RESUME,SUSPEND,BLANK等事件,具体实现在fb_notify.c

总结

1.fb_info代表的一类显示设备(LCD,OLED等),而显示设备的父节点就是显示控制器,
2.通常显示设备的参数以及显示控制器参数会在deviceTree中描述,对于显示设备来讲,描述的是一些时序,对应到fb_info中var参数,控制器参数一般包括显示控制器的中断号,显存位置等
3.显示控制器作为设备挂在platform device的树中,显示控制器驱动 platform driver 通过匹配某些字段,完成match操作,probe函数中,读取平台参数,包括显示控制器的参数,显示设备的参数,调用注册framebuffer,完成设备节点的创建
4.显示控制器一般会关联硬件加速函数,2D,可以部分重写部分framebuffer框架中的一些绘图函数
5.Framebuffer框架作为简单的显示框架,目前已经切换到DRM框架中,为了适应更复杂的图形计算。目前主流的芯片也都基于其框架写显示部分的驱动。但是早期的芯片例如三星2440,6410 还是会有部分的驱动代码
6.DRM框架也是今后的方向

你可能感兴趣的:(linux驱动之子系统)