Framebuffer Analysis for Linux Device Drivers

Source: Internet
Author: User

In the Linux kernel, The framebuffer (POST buffer) driver is the display driver standard. framebuffer abstracts the display device as the POST buffer. After the user maps the memory to the process address space, you can directly perform read/write operations, and write operations can be immediately displayed on the screen. Related display drivers and interfaces are available in Linux kernel/Linux/Drivers/Video, the frmaebuffer driver interface is fbmem. c. This file provides general file operation interfaces for LCD drivers, such as file interfaces that may be applied by applications such as read, write, and IOCTL, the LCD driver of a specific platform can implement its own file operation interface, or directly apply fbmem. the file operation interface provided in C generally applies fbmem. the file operation interface provided by C, because the file operation interface provided by the kernel almost meets our needs, if there are special requirements, you can selectively re-implement the relevant file operation interface. As for how to connect, I will analyze it later.
Before analyzing fbmem. C, let's take a look at several important structures. All the structures used by freambuffer are defined in/include/Linux/FB. h, interested readers can look at the source code, which may be more rewarding, especially the macro definition that ioclt requires. If you do not know the purpose of these macro definitions, then I don't know how to apply the ioctl function in the application to control the LCD to implement related functions.
Skip related macro definitions (for related macro definitions, please check the kernel source code and do not describe it here) define the struct fb_fix_screeninfo struct in row 136th, which is used to describe the attributes of the graphics card, it contains identifiers, cache addresses, and display types. However, when the LCD system runs normally, the value of this struct cannot be modified. Another structure related to the video card is
Struct fb_var_screeninfo struct, used to describe the general features of the video card, such as the actual resolution, virtual resolution, the displacement between the actual resolution and virtual resolution, etc. It can be said that this is a non-important struct, it determines the size and other features of the LCD to be driven.
During LCD display, you usually need to set the color. struct fb_cmap is used to describe the color ing information unrelated to the device. You can use the ioctl operation corresponding to fbiogetcmap and fbioputcmap to set or obtain the color ing information. Some struct structures related to information such as the cursor and image are not described. The relevant fields in each struct are commented in detail in the kernel. I believe my dear readers can understand them.
The famebuffer driver has its own file operation interface fb_ops. The struct is defined in FB. the first row in H is applied to fbmem. c driver interface to write the LCD driver, you do not have to fully implement all the domains, but there are several of the following domains must be implemented.
First:
Void (* fb_fillrect) (struct fb_info * info, const struct fb_fillrect * rect );
This function is used to add a rectangle to the acceleration function of the video card. If the video card does not support hardware addition, it can be replaced by conventional operations, however, you must implement this function in the LCD driver of your specific platform. In fact, this field is only a function pointer field, that is, you cannot set the fb_fillrect batch to null.
The second is:
Void (* fb_copyarea) (struct fb_info * info, const struct fb_copyarea * region );
Used for copying a region.
The third is:
Void (* fb_imageb.pdf) (struct fb_info * info, const struct fb_image * image );
Used to draw an image on the screen.
The fourth is:
INT (* fb_cursor) (struct fb_info * info, struct fb_cursor * cursor );
If you do not want to implement these four functions, you can apply the functions provided by the kernel so that the four function pointers point to these functions respectively. The four functions are cfbcopyarea. cfb_copyarea; cfbfillrect in C. cfb_fillrect and softcursor in C. soft_cursor, cfbimgbit in C. for cfb_imagedbit in C, see the relevant source code file. Therefore, to be precise, these four functions do not have to be implemented by themselves, but do not set the four function pointers to null.
The last and most important struct is struct fb_info, which describes the status of the current video card. fb_info can only be seen in the kernel. struct fb_ops * fbops points to the above struct, used for file operations unique to framebuffer. Modern graphics cards support both single-channel display and multi-channel display. Each display method must have its own independent data zone. Therefore, different display methods can share the video card, therefore, fb_info is used to differentiate the structure of different display methods. Each display method must have its own independent fb_info. If Multiple display methods are supported, the fb_info array or dynamic memory must be defined to allocate multiple fb_info struct variables.
Okay, it's time to analyze fbmem. c. A fb_info array is set at the beginning of this file to support different video cards or display methods, as shown below:
Struct fb_info * registered_fb [fb_max]; in total, fb_max is 32, in FB. h. We can see its macro definition. Here we can look for several important functions to illustrate it. For other functions, please analyze them yourself. Not all analyses are performed here.
Char * fb_get_buffer_offset (struct fb_info * info, struct fb_pixmap * Buf, u32 size) This function application obtains the buffer offset. In this function, the most important thing is synchronous display of I/O, the Code is as follows:
If (BUF-> flags & fb_pixmap_io ){
If (Info-> fbops-> fb_sync & (BUF-> flags & fb_pixmap_sync ))
Info-> fbops-> fb_sync (Info );
Return ADDR;
}
Another piece of code is used to support synchronization.
If (Info-> fbops-> fb_sync & (BUF-> flags & fb_pixmap_sync ))
Info-> fbops-> fb_sync (Info );
Perhaps careful readers may find this sentence Info-> fbops-> fb_sync (Info). This is a function pointer field in the fb_ops struct. As I mentioned in the above analysis, this field can be blank, because in this function, when operating on this field, we first determine whether this field is null. In fact, those fields in fb_ops can be null, so do not think it is null. You can see the source code in fb_mem.c.
In the int fb_show_logo (struct fb_info * info) function, you need to apply the fb_imageb1_field in the fb_ops struct to draw an image on the screen, which is required, in the fb_ops structure, the fb_imageb1_field cannot be null. If it is null, this function cannot be used to complete the function, that is, a useless function. The reference to this function is fbmem. the reference process is as follows:
For (x = 0; x <num_online_cpus () * (fb_logo.logo-> width + 8 )&&\
X <= Info-> var. xres-fb_logo.logo-> width; x + = (fb_logo.logo-> width + 8 )){
Image. dx = X;
Info-> fbops-> fb_imageb.pdf (Info, & image );
}
When the system calls functions such as read, write, open, and release, fbmem is called first. the file interface function implemented in C, and then judge whether the related field in fb_ops is null. If not, then, call the corresponding functions in fb_ops to complete relevant functions. However, for the results of calling IOCTL in an application and the required parameters, see fb_ioctl. This is not described here, because this function is too long and complex, not one or two sentences can be clearly analyzed.
But here is a little trick in fb_read and fb_write functions for data exchange between user space and kernel space. This technique is useful in our programming process, especially when the source address cannot directly exchange data. First, we cannot determine that our data is an integer multiple of 4 bytes. Therefore, we must separate them for processing, which is an integer multiple of 4 bytes. We move four bytes at a time, this is the best for a 32-bit processor like arm, because the addressing speed is the fastest, and the rest can only be moved by one byte, many may think of the application modulo to find less than 4 bytes. For a processor such as arm, modulo and division are difficult because hardware does not directly support special division, therefore, we can only use the shift method for processing. Please carefully analyze the source code, especially if
(C & 3) (used to determine whether it is an integer multiple of 4), for (I = C & 3; I --;) these two statements are useful for processing the buffer. For example, we have a ring buffer that can accommodate eight unsigned int types. When the buffer subscript reaches 8, we need to start from 0. Many people may use the following statement:
If (Index = 8)
Index = 0;
In fact, this has a certain impact on the optimization of code efficiency, of course, it is not very big, but in a project, the major impact is from a small impact, so, we 'd better use such a statement to replace it, so that the task can be completed better: Index & = 0x7; can you see how to do it, if the value of the index is within the range of 7, it will not be changed, but if the value is 8, that is, 0x8, it will be known as the binary value, the binary value of 0x8 is (1000), while the binary value of 0x7 is (0111), so bitwise and of course return to 0. However, there is a condition for applying this technique, that is to say, the buffer size must be 2 to the power to apply this technique correctly. Well, I will not explain this technique, but pay attention to it, every small optimization is a great optimization for the entire project. If you are interested in code optimization, you can refer to the book "ARM Embedded System Development-software design and optimization", which is recommended by my teacher. Part of the Code for fb_read to process data is as follows:
While (count ){
C = (count> page_size )? Page_size: count;
DST = buffer;
For (I = C> 2; I --;)
* DST ++ = fb_readl (SRC ++ );
If (C & 3 ){
U8 * dst8 = (u8 *) DST;
U8 _ iomem * src8 = (u8 _ iomem *) SRC;

For (I = C & 3; I --;)
* Dst8 ++ = fb_readb (src8 ++ );

Src = (u32 _ iomem *) src8;
}

If (copy_to_user (BUF, buffer, c )){
Err =-efault;
Break;
}
* PPOs + = C;
BUF + = C;
CNT + = C;
Count-= C;
}
A very classic short piece of code, please digest it slowly. One of the biggest gains from the Linux kernel source code is to learn a lot of classic algorithms that are useful in actual programming, sometimes it may be a critical factor for a project.
The fb_mmap function is also one of the most important functions of the LCD driver. readers who have read the LCD controller in arm know that video memory exists in general graphics cards, but for embedded systems, almost no one will integrate the video card on the CPU. Therefore, generally, the application memory is mapped to the LCD memory address, you can use DMA or other methods to display the buffer content without going through the CPU. Because the image, video, and other data are very large, if the CPU is used for direct processing, the CPU may be very heavy and may not be satisfactory. Similarly, between the Linux kernel and applications, to reduce the time required for the kernel to first copy data from applications to the kernel space (note the differences between the user space and the kernel space), memory ing is also required, the purpose is to enable both the user space and the kernel space to apply the memory directly, and combine the linxu kernel space with the user space memory and application memory into LCD memory, we can know how much this function is used. First, it completes the user space and the kernel space, and can directly use the internal memory. At the same time, It maps the memory to the LCD Memory, the application can read and write the memory directly, and the display is immediately displayed on the LCD screen. For example, if you want to write a photo to the memory, you can immediately display the photo on the LCD. I will give you an example at the end, that is, an example of displaying the photo. For more information about how this function is implemented, see the source code. For more information about how an application applies the MMAP function, see related documents. It is not described in detail here.
This file also provides two functions for us to register and deregister the LCD Driver for our specific platform. Int register_framebuffer (struct fb_info * fb_info), which is used to register the LCD driver of a specific platform. Int unregister_framebuffer (struct fb_info * fb_info) is used to cancel the LCD driver of a specific platform. For the function of this file, please check the source code and analyze it. Do not describe it here.
In the video directory, there is also a skeletonfb. c file. This file is a framework that describes how to use the register_framebuffer and unregister_framebuffer functions provided by fb_mem.c to implement the development process of the LCD driver on a specific platform, if you can understand this file, you can create an LCD driver for a specific platform based on this file. In this directory, there are many other LCD drivers, such as sa1100fb. c. This is a strongarm 1100 LCD driver and a vfb. c. This virtual LCD driver, in fact, many source codes in the Linux kernel are very useful. We can apply or modify them directly, the problem is that you must clearly understand the differences between your needs and the hardware features of the driver in the kernel source code and what you need, and modify these differences for your use. However, this is also the difficulty, unlike other programs, if C is not good enough, and the entire kernel driver architecture cannot Solution (or a subsystem does not know). It is difficult to understand the kernel source code, and it is more difficult to modify it.
For friends who use S3C2440 or S3C2410, you can directly apply the s3c2410fb provided by the kernel. c. This is an LCD driver that is useful for both S3C2440 and S3C2410. If it has been compiled into the kernel, the General Directory is/dev/FB/0. Of course, this may not be the case, please check the relevant information. That is to say, we can directly use the open function in the application to open this device file, so that we can directly operate the LCD display. S3c2410fb. c is the author's reference to skeletonfb. c, sa1100fb. C and other related drivers are written in one sentence, read, modify, and use it. This may be the most common thing for Linux device driver development, or perhaps one of the reasons why Linux is popular in embedded systems, as mentioned above, it is very difficult to understand. The implementation process of s3c2410fb. C is similar to that of skeletonfb. C. Read the LCD controller section in the skeletonfb. C and S3C2410 or S3C2440 manuals.
In s3c2410fb. in C, it should be noted that the static void s3c2410fb_set_lcdaddr function is actually completed, and the memory of the user space and the kernel space is mapped to LCD memory. So here we will provide a detailed description, in the LCD controller section of the S3C2440 manual, we can see the lcsaddr1 register, which is mainly used to store the starting address of the LCD memory, but we only use 1 to 30, so, we need to shift the memory start address to the right. The instructions on lcdsaddr1 are as follows:
Lcdbank [29:21]: these bits indicate a [30: 22] of the bank location for the video buffer in the system memory. lcdbank value cannot be changed even when moving the view port. LCD frame buffer shoshould be within aligned 4 MB region, which ensures that lcdbank Value
Will not be changed when moving the view port. So, care shocould be taken to use the malloc () function.
Lcdbaseu [20:0]: for dual-scan LCD: these bits indicate a [21:1] of the Start address of the upper address counter, which is for the Upper Frame Memory of dual scan LCD or the Frame Memory of single scan LCD.
For single-scan LCD: these bits indicate a [21:1] of the Start address of the LCD frame buffer.
So in this function, the memory address is shifted to the right, and the source code is:
Saddr1 = FBI-> FB. Fix. smem_start> 1;
The processing of the lcdsaddr2 register is quite cumbersome. We start with the CPU manual. In the CPU manual, the description of lcdsaddr2 is as follows:
Lcdbasel [20:0]: for dual-scan LCD: these bits indicate a [21:1] of the Start address of the lower address counter, which is used for the lower frame memory
Of dual scan LCD.
For single scan LCD: these bits indicate a [21:1] of the end address of the LCD frame buffer.
Lcdbasel = (the frame end address)> 1) + 1
= Lcdbaseu +
(Pagewidth + offsize) x (lineval + 1)
We can see from the source code that we use the single scan method. Therefore, a [21:1] should be the end address of the LCD display. This function handles the following:
Saddr2 = FBI-> FB. Fix. smem_start;/* start address */
Saddr2 + = (Var-> xres * var-> yres * var-> bits_per_pixel)/8;/* buffer size */
Saddr2> = 1;/* execute (the frame end address)> 1 )*/
Note that the above Code does not perform the Add 1 operation.
The processing of lcdsaddr3 is much simpler. This register only processes the related offsize pagewidth. Let's start with the CPU manual. The description is as follows:
Offsize [21:11] virtual screen offset size (the number of half words ). this value defines the difference between the address of the last half word displayed on the previous LCD line and the address of the first half word to be displayed in the new LCD line.
Pagewidth [10: 0] virtual screen page width (the number of half words). This value defines the width of the view port in the frame.
Therefore, the function only calls related macros for processing. The source code is as follows:
Saddr3 = s3c2410_offsize (0) | s3c2410_pagewidth (Var-> xres );
After finding the values required in the three registers, write the values to the relevant registers. The source code is as follows:
Writel (saddr1, s3c2410_lcdsaddr1 );
Writel (saddr2, s3c2410_lcdsaddr2 );
Writel (saddr3, s3c2410_lcdsaddr3 );
At this point, this function has been analyzed and will be explained here. When looking at the kernel-related source code, please check the relevant chip manual. If you do not know the chip function, it is mainly about the time sequence required by the chip, the specification of the relevant register values, and the functions. You only understand a string and do not know its meaning and driver functions.
For the processing of the video card, that is, the color processing method, because the color mode of s3c2410fb is 16bpp, we can view the S3C2440 or S3C2440 CPU manual, the 16bpp color model is described as follows:
16 BPP color mode
16 bits (5 bits of red, 6 bits of green, 5 bits of blue) of video data correspond to 1 pixel. but, STN controller will use only 12 bit color data. it means that only upper 4bit each color data will be used as pixel data (R [], G [], B []). the following
Table shows color data format in words:
Therefore, the corresponding var struct variable fields also need to correspond to this field. The following processing is done in the s3c2410fb_check_var file:
If (Var-> bits_per_pixel = 16 ){
VaR-> Red. offset = 11;
VaR-> green. offset = 5;
VaR-> blue. offset = 0;
VaR-> Red. Length = 5;
VaR-> green. Length = 6;
VaR-> blue. Length = 5;
VaR-> Transp. Length = 0;
} Else {
VaR-> Red. Length = 8;
VaR-> Red. offset = 0;
VaR-> green. Length = 0;
VaR-> green. offset = 8;
VaR-> blue. Length = 8;
VaR-> blue. offset = 0;
VaR-> Transp. Length = 0;
}
For the three colors red, green, and blue as the base colors, they represent the order and rules in 1 word. Please check the relevant information on your own. For other functions, refer to the relevant chip manual for independent analysis. In s3c2410fb. C, I personally think that these two points are difficult because they are not so intuitive. You need to convert it to understand it.
For an application, you must define the relevant struct variables to implement IOCTL. If necessary, you must define the fb_var_screeninfo and fb_fix_screeninfo struct variables, because we need to obtain the driver information, for example, the display area size, pixels, and other important information, which must be used for memory ing, because if we do not know the pixel, the display area size, we cannot accurately map the memory, therefore, the internal read/write will not make much sense. I can correctly display pictures when writing an application test program. However, after adding ASCII and Chinese character libraries, I want to simply display ASCII and Chinese characters. However, I did not succeed, I don't know why, but bare metal devices won't work either. That is, images can be displayed normally and no characters can be displayed. I have done a bare metal LCD Driver experiment and now I can only view pictures, this also disrupted my plan because I wanted to design a clock system based on the Linux operating system (apply the relevant GUI to draw a time clock on the LCD and display the week, at the same time, real-time temperature must be displayed) as the course design for embedded system courses. Maybe there is something wrong with LCD. I am looking for an answer. If the friend has seen this problem and solved it, please tell me that I need to know the problem urgently.
Well, it took me a whole night to stop writing, but I am happy to write, because I am used to recording the understanding of every knowledge point, the device driver documentation, and it has been a long time, can be used as a review material. At the same time, it can also improve the writing capability of personal documents. Especially in the embedded field, drivers often do not write related applications. This requires that the interfaces provided by the white driver to the application, such as the macro definition and functions required for the application IOCTL; the size of the memory address required for reading and writing, the special data structure required, and the value to be read. The value does not need to be further transformed. How should we convert the value if necessary. For example, a DS18B20 driver uses its read temperature value as an example. Since user space and kernel space can only transmit char data, a 16-bit temperature value must be read separately for two values, among the two values read, one is a low 8-bit value, and the other is a high 8-bit value. Otherwise, how can someone combine the data.
After talking a lot, I still feel that I have not explained it. This may be my own level, but what I mentioned above is what I can do now. If there are any mistakes, please correct me and give me the opportunity to learn and correct. the Linux operating system is open-source.
At the same time, if you want to study the console-related drivers, if you are interested in learning together, framebuffer may learn later. There is a subdirectory under the video directory, the Console Directory, which contains some drivers related to the console. In particular, there are a large number of font libraries under this directory, of course, there is no Chinese, there is a 16*16 Chinese Character Library in the UCOS operating system experiment provided by the mini2440 Development Board. There are many other types of Chinese character libraries on the Internet, but the key is to have instructions for use,

If you need the source code for your experiment and a friend who discusses the problem with me, please contact me. I would like to find a few friends to study with me, I don't know who else is learning this direction in our school, so I am the only one I know. A person's learning experience is really unappealing, and his progress is also very slow. Because of any problems, he always wants to find his own materials. Sometimes someone else can solve the problem in one sentence, it may take several hours or days for me to solve the problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.