Writing Linux LCD drivers
——本文深入地分析了framebuffer设备驱动的结构
作者:JimSheng
Writing Linux LCD drivers
Abstract
1 LCD ModuleDriverController
2 Linux Frame Buffer Driver
2.1 Why Frame Buffer?
2.2 What is Frame Buffer Devices?
2.3 How to Write Frame Buffer Device Drivers?
3 Analysis of Linux Frame Buffer Driver Source Codes
3.1 fb.h
3.2 fbmem.c
4 Skeleton of LCD controller rivers
4.1 Allocate a system memory as video memory
4.2 Implement the fb_ops functions
Reference
Abstract
This material discusses how to write a Linux frame buffer LCD device driver.
1 LCD ModuleDriverController
Besides the datasheet of LCD devices, there are two quite good books
(.pdf format) on LCD technology. Both of them are written in Chinese.
One is “液晶显示技术”, and the other is “液晶显示器件”. The two books give almost
all needed LCD knowledge, including introductions to hardware
implementation of LCD devices and low level software programming used
to operate LCD devices. This helps LCD circuits design and low level
LCD programming.
2 Linux Frame Buffer Driver
2.1 Why Frame Buffer?
If GUIs (Graphic User Interface) such as MiniGUI, MicroWindows are
used, LCD device drivers must be implemented as Linux frame buffer
device drivers in addition to those low level operations which only
deal with commands provided by LCD controllers.
2.2 What is Frame Buffer Devices?
The frame buffer device provides an abstraction for the graphics
hardware. It represents the frame buffer of some video hardware and
allows application software to access the graphics hardware through a
well-defined interface, so the software doesn't need to know anything
about the low-level (hardware register) stuff.
The device is accessed through special device nodes, usually located in the /dev directory, i.e. /dev/fb*.
More description about frame buffer device can be found in two txt
files: linux /Documentation /fb /framebuffer.txt and linux
/Documentation /fb /interal.txt
2.3 How to Write Frame Buffer Device Drivers?
There are few instructive materials about writing frame buffer device
drivers. You may find “Linux Frame buffer Driver Writing HOWTO” at this
web page http: /linux-fbdev.sourceforge.net /HOWTO /index.html, but the
HOWTO is somewhat curt and not enough. So having a look into Linux
source codes is necessary. The next section is an analysis of the
related source codes.
3 Analysis of Linux Frame Buffer Driver Source Codes
Linux implements Frame Buffer Drivers mainly based on the groundwork of these two files:
1) linux/include/linux/fb.h
2) linux/drivers/video/fbmem.c
It’s time to have a close look at them.
3.1 fb.h
Almost all important structures are defined in this file. First let me
describe what each means and how they are used one by one.
1) fb_var_screeninfo
It is used to describe the features of a video card you normally can
set. With fb_var_screeninfo, you can define such things as depth and
the resolution you want.
struct fb_var_screeninfo {
__u32 xres; /* visible resolution */
__u32 yres;
__u32 xres_virtual; /* virtual resolution */
__u32 yres_virtual;
__u32 xoffset; /* offset from virtual to visible */
__u32 yoffset; /* resolution */
__u32 bits_per_pixel; /* guess what */
__u32 grayscale; /* != 0 Graylevels instead of colors */
struct fb_bitfield red; /* bitfield in fb mem if true color, */
struct fb_bitfield green; /* else only length is significant */
struct fb_bitfield blue;
struct fb_bitfield transp; /* transparency */
__u32 nonstd; /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* acceleration flags (hints) */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (pico seconds) */
__u32 left_margin; /* time from sync to picture */
__u32 right_margin; /* time from picture to sync */
__u32 upper_margin; /* time from sync to picture */
__u32 lower_margin;
__u32 hsync_len; /* length of horizontal sync */
__u32 vsync_len; /* length of vertical sync */
__u32 sync; /* see FB_SYNC_* */
__u32 vmode; /* see FB_VMODE_* */
__u32 reserved[6]; /* Reserved for future compatibility */
};
2) fb_fix_screeninfon
It defines the properties of a card that are created when you set a
mode and can't be changed otherwise. A good example is the start
address of the framebuffer memory. This can depend on what mode is set.
Now while using that mode, you don't want to have the memory position
change on you. In this case, the video hardware tells you the memory
location and you have no say about it.
struct fb_fix_screeninfo {
char id[16]; /* identification string eg "TT Builtin" */
unsigned long smem_start; /* Start of frame buffer mem */
/* (physical address) */
__u32 smem_len; /* Length of frame buffer mem */
__u32 type; /* see FB_TYPE_* */
__u32 type_aux; /* Interleave for interleaved Planes */
__u32 visual; /* see FB_VISUAL_* */
__u16 xpanstep; /* zero if no hardware panning */
__u16 ypanstep; /* zero if no hardware panning */
__u16 ywrapstep; /* zero if no hardware ywrap */
__u32 line_length; /* length of a line in bytes */
unsigned long mmio_start; /* Start of Memory Mapped I/O */
/* (physical address) */
__u32 mmio_len; /* Length of Memory Mapped I/O */
__u32 accel; /* Type of acceleration available */
__u16 reserved[3]; /* Reserved for future compatibility */
};
3) fb_cmap
Device independent colormap information. You can get and set the colormap using the FBIOGETCMAP and FBIOPUTCMAP ioctls.
struct fb_cmap {
__u32 start; /* First entry */
__u32 len; /* Number of entries */
__u16 *red; /* Red values */
__u16 *green;
__u16 *blue;
__u16 *transp; /* transparency, can be NULL */
};
4) fb_info
It defines the current state of the video card. fb_info is
only visible from the kernel. Inside of fb_info, there exist a fb_ops
which is a collection of needed functions to make driver work.
struct fb_info {
char modename[40]; /* default video mode */
kdev_t node;
int flags;
int open; /* Has this been open already ? */
#define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct fb_cmap cmap; /* Current cmap */
struct fb_ops *fbops;
char *screen_base; /* Virtual address */
struct display *disp; /* initial display variable */
struct vc_data *display_fg; /* Console visible on this display */
char fontname[40]; /* default font name */
devfs_handle_t devfs_handle; /* Devfs handle for new name */
devfs_handle_t devfs_lhandle; /* Devfs handle for compat. symlink */
int (*changevar)(int); /* tell console var has changed */
int (*switch_con)(int, struct fb_info*);
/* tell fb to switch consoles */
int (*updatevar)(int, struct fb_info*);
/* tell fb to update the vars */
void (*blank)(int, struct fb_info*); /* tell fb to (un)blank the screen */
/* arg = 0: unblank */
/* arg > 0: VESA level (arg-1) */
void *pseudo_palette; /* Fake palette of 16 colors and
the cursor's color for non
palette mode */
/* From here on everything is device dependent */
void *par;
};
5) struct fb_ops
User application program can use ioctl() system call to operate low LCD
hardware. Methods defined in fb_ops structure are used to support these
operations.
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);
/* get non settable parameters */
int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
/* get settable parameters */
int (*fb_get_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* set settable parameters */
int (*fb_set_var)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* get colormap */
int (*fb_get_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* set colormap */
int (*fb_set_cmap)(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
/* pan display (optional) */
int (*fb_pan_display)(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
/* perform fb specific ioctl (optional) */
int (*fb_ioctl)(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg, int con, struct fb_info *info);
/* perform fb specific mmap */
int (*fb_mmap)(struct fb_info *info, struct file *file, struct vm_area_struct *vma);
/* switch to/from raster image mode */
int (*fb_rasterimg)(struct fb_info *info, int start);
};
6) structure map
struct fb_info_gen | struct fb_info | fb_var_screeninfo
| | fb_fix_screeninfo
| | fb_cmap
| | modename[40]
| | fb_ops ---|--->ops on var
| | ... | fb_open
| | | fb_release
| | | fb_ioctl
| | | fb_mmap
| struct fbgen_hwswitch -|-> detect
| | encode_fix
| | encode_var
| | decode_fix
| | decode_var
| | get_var
| | set_var
| | getcolreg
| | setcolreg
| | pan_display
| | blank
| | set_disp
[编排有点困难,第一行的第一条竖线和下面的第一列竖线对齐,第一行的第二条竖线和下面的第二列竖线对齐就可以了]
struct fbgen_hwswitch is an abstraction of hardware operations. It is not necessary, but sometimes useful.
3.2 fbmem.c
fbmem.c is at the middle place of frame buffer driver architecture. It
provides system calls to support upper user application programs. It
also provides an interface to low level drivers for specific hardware.
Those low level frame buffer drivers can register themselves into the
kernel by this interface. fbmem.c implements the common codes used by
all drivers, thus avoids repeated work.
1) Global Varibles
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
The two are used to record on-using instance of fb_info structure.
fb_info represents the current state of video card. All fb_info
structures are globally placed in an array. When a frame buffer
registers itself to kernel, a new fb_info is added to this array and
num_registered_fb increases 1.
static struct {
const char *name;
int (*init)(void);
int (*setup)(void);
} fb_drivers[] __initdata= { ....};
If frame buffer driver is static linked into kernel, a new entry must
be added to this table. If use insmod/rmmod, don’t care this.
static struct file_operations fb_ops ={
owner: THIS_MODULE,
read: fb_read,
write: fb_write,
ioctl: fb_ioctl,
mmap: fb_mmap,
open: fb_open,
release: fb_release
};
This is the interface to user application programs. fbmem.c implements these functions here.
2) register_framebuffer(struct fb_info *fb_info)
unregister_framebuffer(struct fb_info *fb_info)
This is the interface to low level frame buffer device driver. The
drivers use this pair of functions to register or unregister
themselves.
Almost all the work those low level drivers needed to do is to fill in an fb_info structure and then to (un)register it.
4 Skeleton of LCD controller rivers
LCD drivers operate LCD device hardwares, while fbmem.c records and
administrates these drivers. There is a skeleton frame buffer driver in
linux /drivers /fb /skeleton.c. It shows how to implement a frame
buffer driver with very few codes. Because it is too simple, it does
nothing but filling an fb_info and then (un)registering it.
In order to implement a usable LCD controller driver, something else
must be added into it. But what should be added? As we all know, device
drivers abstract hardware and provide system call interface to user
programs. So we can implements the low level hardware operations
according to the need of the system call interface, namely the
file_operations structure which is discussed in section 3.2.
4.1 Allocate a system memory as video memory
After a careful lookup in fbmem.c, we know that open() and release()
method of file_operations structure do not need low level support,
while read(), write() and mmap() need a common support function
fb_get_fix(). So fb_get_fix() must be provided by driver writers.
Additionally the writer should allocate a system memory as video
memory, for most LCD controllers have no their own video memory. The
allocated memory start address and length are later placed in
smem_start and smem_len fields of fb_fix_screeninfo structure. The
allocated memory should be physically consecutive.
4.2 Implement the fb_ops functions
The only method of file_operations still not discussed is ioctl(). User
application programs use ioctl() system call to operate LCD hardware.
Methods defined in fb_ops structure(section 3.1) are used to support
these operations. NOTE: fb_ops structure is NOT file_operations
structure. fb_ops is for abstraction of low level operations, while
file_operations is for upper level system call interface
Again we’d better first decide which methods should be implemented.
ioctl() system call is implemented in fbmem.c, so we turn to it and
quickly we can find out such relationship between ioctl() commands and
fb_ops’s methods:
FBIOGET_VSCREENINFO fb_get_var
FBIOPUT_VSCREENINFO fb_set_var
FBIOGET_FSCREENINFO fb_get_fix
FBIOPUTCMAP fb_set_cmap
FBIOGETCMAP fb_get_cmap
FBIOPAN_DISPLAY fb_pan_display
Now we know that if we implement these fb_XXX_XXX functions, then user
application writers can use FBIOXXXX micros to operate LCD hardwares.
But how can we implement them?
It is fine to have a reference to linux/drivers/video/fbgen.c or other drivers under the linux/drivers/video directory.
Among these functions, fb_set_var() is the most important. It is used
to set video mode and more. The following is the common steps performed
by a fb_set_var() function:
1) Check if mode setting is necessary
2) Set the mode
3) Set colormap
4) Reconfigure the registers of LCD controller according former settings
The fourth step shows where low level operations are placed. Curious
men may have such a question: how image data of user application are
put onto the screen. Driver writer allocates a system memory as video
memory, and later he sets the start address and length of the memory to
LCD controller’s registers(often in fb_set_var() function). The content
of the memory will be sent to screen automatically by LCD
controller(for details, see specific LCD controller). On the other
hand, the allocated system memory is mapped to user space by mmap().
Thereby, when a user sends data to the mapped memory, the data will be
shown on LCD screen.
Reference
1 液晶显示技术
2 液晶显示器件
3 linux/Documentation/fb/framebuffer.txt
4 linux/Documentation/fb/interal.txt
5 Linux Framebuffer Driver Writing HOWTO
http:/linux-fbdev.sourceforge.net/HOWTO /index.html
6 linux/include/linux/fb.h
7 linux/drivers/video/fbmem.c
8 linux/drivers/video/skeletonfb.c
9 linux/drivers/video/fbgen.c
10 linux/drivers/video/tgafb.c
11 s3c2410 microprocessor user manual
s3c2410fb.h, s3c2410fb.c, s3c2410fb.c-pre, s3c2410fb.c-mono
A kind of arm-based widely used MCU, with integrated LCD controller.
12 sed1335 datasheet
A kind of widely used LCD controller