Linux Framebuffer Driver Analysis Part 2 - Driver Framework, Interface Implementation and Use

In-depth analysis of the driver framework, interface implementation and use of the LinuxFramebuffer subsystem.

First, the software requirements of LinuxFramebuffer

The previous article elaborated on the software requirements of LinuxFramebuffer (please understand the first article before reading this article), summarized as follows:

1. Program the LCD control registers of the SOC to support different LCD screens to maximize the application scenarios of the SOC. This is a hardware platform dependent requirement. It corresponds to the implementation content in the Linux source path arch\arm\mach-s5pv210\XXX210-lcds.c.

2. Provide the user with an interface (mmap) that maps the process space to the actual display physical memory, so that the application can display the image resource on the LCD screen with one copy. This requires the support of the MMU (memory management unit) of the SOC, the memory management of the Linux operating system , and the SDRAM (memory) of the SOC. Since memory management is a common part of the operating system, it provides independent interfaces to other subsystems. So we can think that the framebuffer implements the mapped interface by calling the memory management interface, which is a non-platform-related requirement.

3.Framebuffer supports 32 display buffers. It is abstracted internally, that is, it is unified and abstracted to the upper-layer application as a character master device, and different display caches are regarded as different character slave devices. The management of the display slave device belongs to the function of the Framebuffer internal frame.

4. Linux device drivers support various types of device drivers, including Framebuffer, input, USB, watchdog, MTD, etc. These different types of devices are generally expressed as different master devices. The management of different master devices is done by the Linux device driver framework. In addition, since Linux also considers the device as a file, a layer of virtual file system (VFS) is also set up on the device driver. Therefore, in fact, the application layer interacts with the VFS interface corresponding to the framebuffer. As shown below:

For driver developers, it is only necessary to perform the first part of register programming ( red part) for a specific hardware platform SOC and a specific LCD (soldered to the pins of the SOC) . The second, third, and fourth parts (green parts) have been abstracted and implemented in the Linux driver release source code. LCD driver developers only need to understand the internal framework and interface usage of the framebuffer. In fact, for other device drivers, including buttons, touch screens, SD cards, usb, etc., Linuxdriver has already implemented most of the non-platform-related requirements and tasks, and developers also only need to understand the internal framework and interface usage of the driver. That's it.

Next, we will analyze in detail how LinuxFramebuffer supports the second and third requirements. It corresponds to the implementation content such as driver\video\fbmem.c. First analyze the third point driver framework, and then analyze the mapping interface.

Second, the internal driver framework of LinuxFramebuffer

1. Initialize

--driver\video\fbmem.c

As a subsystem, Framebuffer registers a character device driver with a major device number of 29 to the system through the register_chrdev interface in fbmem_init. Create a graphics device class through class_create, and cooperate with the mdev mechanism to generate a device file (located in the /dev directory) for user access.  See " Linux Device File Creation and mdev " for details on device files and mdev mechanism .

The definition of the interface set fb_fops driven by the Framebuffer device is:

In the linux device driver, all display cache devices are managed internally by the framebuffer subsystem, that is, the linux device driver framework only recognizes one framebuffer device with a major device number of 29. All accesses to the display cache (up to 32) at the application layer will be pushed to fb_fops for further distribution operations.

2.     register_framebuffer

单个显示缓存视为一个framebuffer从设备,其在驱动加载初始化时需要通过register_framebuffer接口向framebuffer子系统注册自己。这样,当应用层要访问该从设备时,才能通过framebuffer子系统进行操作管理分发。我们跟踪一下:


每个从设备都需要传递一个fb_info的数据结构指针,其即代表单个显示缓存设备。从中,可以看到fb_info最终会存储到全局数组struct fb_info*registered_fb[FB_MAX]中,FB_MAX是32,从这里我们也可以看出,framebuffer最多支持32个从设备。另外,每个从设备注册还会在/sys/class/graphics/设备类中创建一个设备,最终由mdev在/dev/目录中生成对应的设备文件。假设M个从设备调用register_framebuffer接口,即会在/dev中生成M个设备文件,如/dev/fb0、/dev/fb1、/dev/fb2等等。这M个设备的主设备号都是29,从设备则是0、1、2等等。

3.     fb_info结构体

fb_info结构体代表单个显示缓存从设备,在调用register_framebuffer接口之前,必须要初始化其中的重要数据成员。其定义如下:

其中,fb_var_screeninfo和fb_fix_screeninfo两个结构体跟LCD硬件属性相关,fb_var_screeninfo代表可修改的LCD显示参数,如分辨率和像素比特数;fb_fix_screeninfo代表不可修改的LCD属性参数,如显示内存的物理地址和长度等。另外一个非常重要的成员是fb_ops,其是LCD底层硬件操作接口集。

fb_ops硬件操作接口集包含很多接口,如设置可变参数fb_set_par、设置颜色寄存器fb_setcolreg、清屏接口fb_blank、画位图接口fb_imageblit、内存映射fb_mmap等等。

fb_info结构体在调用register_framebuffer之前完成初始化。一般来说,LCD设备属于平台设备,其初始化是在平台设备驱动的probe接口完成。而LCD设备所涉及的硬件初始化(第一部分需求)则在平台设备初始化中完成。有关平台设备驱动的分析,笔者会另写一篇文章阐述。

4.     fb_open接口

当一个framebuffer设备完成初始化时,其对应的fb_info结构体会在全局数组registered_fb中记录,并且位于跟从设备号相等的位置上;而且,在/dev目录下也会生成一个/dev/fbx的设备文件。以下分析假设是访问第一个framebuffer设备:

对于应用层open(“/dev/fb0”,…)访问该framebuffer设备来说,vfs先通过设备名(/dev/fb0)获得该设备的主设备(29)和从设备号(0)。而linux设备驱动框架则通过主设备29找到该设备对应的设备驱动接口集fb_fops。Linux驱动框架的分析过程请看《Linux字符设备驱动剖析》。接着linux设备驱动框架会调用fb_fops的fb_open,我们来跟踪一下:


这个接口很简单,即是次设备号在全局数组registered_fb中找出对应的fb_info数据结构,将其设置到file指针的私有数据中,便于之后用户访问调用其他接口如mmap、ioctl等能够直接找到对应的fb_info。最后也会调用fb_info->fb_ops->fb_open,不过这个接口一般没干啥,赋值为NULL即可。

所以,framebuffer子系统内部驱动框架即负责通过从设备号找到对应的从设备(具体LCD操作接口所在的fb_info)。

5.     驱动框架总结

经过上面的分析,这张图应该很容易理解了。

三、mmap映射

framebuffer驱动最重要的功能就是给用户提供一个进程空间映射到实际的显示物理内存的接口(mmap)。当用户图像数据buffer和内核虚拟地址空间buffer对应的都是同一块物理内存时,资源数据拷贝到用户图像数据buffer时,即是直接拷贝到显示物理内存了。

应用层mmap映射接口会经历以下层次调用:

1.     sys_mmap

sys_mmap是虚拟文件系统层的映射实现,其会在用户进程虚拟空间(0到3G)申请一块虚拟内存,最终会调用到framebuffer子系统的fb_mmap,并向其传递vm_area_struct结构体指针,该结构体已经包括进程用户空间的内存地址信息。

Vfs虚拟文件系统是linux系统的重要组成部分,这里不再展开,以后再分析。

2.     fb_mmap

来跟踪一下:

该接口也是找到具体的从设备对应的LCD操作接口集,并调用fb_mmap接口。

我们选一个具体的LCD的接口实现看看:

remap_pfn_range接口即是建立进程地址空间(0到3G)到实际的显示物理内存的映射。其中,lcd_mem是fb_info结构体初始化使用kzmalloc申请的,其代表内核态(3G到4G)的虚拟内存首地址。而virt_to_phys即是将虚拟地址转化为物理地址,更新vm_area_struct的数据成员,而其最终会影响进程的页表设置,进而影响MMU的设置。

当该接口完成之后,最终向应用层返回进程空间的内存首地址(0到3G)。这样,应用层即可以直接访问这块内存,进行读写操作。其直接通过MMU来访问实际的物理地址,而不需要再经过驱动的管理。

四、接口使用

       如下,操作是不是很简单?不过,大家要记得,framebuffer只负责位图显示,而很多图像都是有编码格式的,如JPG等等,需要先解码,再送给framebuffer。

After writing so much, I found that by writing another article on how to develop LCD drivers, to realize the first part of the framebuffer requirements, in order to link the previous analysis of the driver framework, I will have a clearer grasp of the ins and outs of the LCD driver and framebuffer subsystem. . This can be arranged after the analysis of the platform device driver, because most of the drivers are platform device drivers, we should first talk about the platform device driver framework, and then go back to the LCD driver development, including the parts related to the LCD platform device (GPIO resources, Interrupt resource configuration, etc.) and LCD driver part.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325988580&siteId=291194637