|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
貌似好久好久没写驱动类的博客,距上一次写驱动的博客还得回到半年前,那时天气还很冷,如今已经热的要命,但我还是想把自己学习到的知识跟大家分享。没写驱动类的博客是觉得Linux下的驱动源码真是太多太多了,半年前我也比较害怕Linux源代码,随时时间的推移,自己琢磨了不短时间了,觉得大概能读懂Linux源代码了,也就没那么害怕它了。! ]- W3 @3 c- x: m
0 o: S- i1 v/ ~% v
原归正传,预定以后的驱动博客我想用尽量短篇幅来记录,但是会以尽量详细的角度去分析驱动。学习驱动心得,驱动呢主要还是要抓住主干的架构,太细节的东西不必太刻意去研究,因为很多太底层的函数人家已经帮你实现了,你不必去怀疑它正确与否。/ D" a9 M$ [5 Y: H y# U
# d0 O8 ?1 i! n( {$ X7 x, q, x
LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作。用户根本不用关心物理显示缓冲区的具体位置及存放方式,因为这些都由缓冲区设备驱动完成了。
. ^5 K& R8 b/ g; s2 w4 k. f
" `8 A( w/ X; y7 J1 J( }5 x9 p; d启动开发板后执行ls /dev/fb* 命令可以看到,帧缓冲设备的主设备号为29,对应/dev/fbn设备文件,一般为/dev/fb0+ O% W+ q9 c5 n
( M$ J6 X9 @! [8 G3 O9 f
在弄清楚LCD驱动架构之前,我们先弄清楚几个重要的结构体,为了减短篇幅,有一些不是很重要的成员会用省略,具体的源代码请大家参考Linux源代码,这里我使用的源代码是天嵌公司提供的移植好的Linux-2.6.30.4。& }' R- h/ P2 D9 X
3 ~& R( T% T! {! U% N5 z7 S% Q1.fb_info结构体(在include/linux/fb.h文件里定义)& P- `, h0 j* s
8 v% z. L4 b0 Z h( d: X5 G, Y
struct fb_info {
+ ^ o$ @3 ?7 Gint node; /* 序号索引值,/dev/fb0,/dev/fb1 其中0,1 就是从这里获得的*/
7 {* t! S# J3 V Lint flags;0 L0 K/ A! k# X5 @2 u, R2 s
struct mutex lock;/* 一般在 open/release/ioctl 函数里会用到的锁 */
1 _& A) M# y1 ~ r4 Z4 Ustruct fb_var_screeninfo var;/* 可变参数,很重要 */6 W# n: X3 L1 w- p4 {4 k$ z
struct fb_fix_screeninfo fix; /* 固定参数,很重要 */
9 l" g- k+ s/ j: A% W* Wstruct fb_monspecs monspecs;/* Current Monitor specs */" z+ l$ a4 u2 Z: f
struct work_struct queue; /* Framebuffer event queue */
' w0 K2 `3 x& s- e* o1 X$ Rstruct fb_pixmap pixmap; /* Image hardware mapper */
! Q% a: i( [1 X' i& z& rstruct fb_pixmap sprite; /* Cursor hardware mapper */
4 [, G1 D) \. R! b6 E: Pstruct fb_cmap cmap; /* Current cmap *// n4 U! c! |! _3 A8 r) ~
struct list_head modelist; /* mode list */
0 Y b3 w( r( l o* Xstruct fb_videomode *mode;/* current mode */$ w2 W2 G* _3 s
; T, f) Z' Y! u3 f" h9 ]; |。。。。。。
9 S- _' b8 H9 @0 B( d* r. X- V1 ]+ V5 {6 y m8 _( F* Z
struct fb_ops *fbops;5 p7 X* [% p4 ]1 s; Q* G3 Y2 l
struct device *device;/* This is the parent */6 {: h1 l! |0 h& U, t$ l
struct device *dev;/* This is this fb device */% e$ b: E0 v) P( n& H3 j* F
! }, z) O3 P& j# y; e8 {3 s0 k N。。。。。。
. {" M" q* T9 cchar __iomem *screen_base;/* "显存“的基地址 */; S- c5 V2 k" U$ |& X
unsigned long screen_size; /* ”显存“的大小 */ ( o1 R3 @/ Z, m5 C# ^
void *pseudo_palette; /* 16位假的调色板 */
9 R+ {2 U3 x2 s#define FBINFO_STATE_RUNNING 0+ Y7 l5 H( k: A) _0 ~* D2 ~1 P
#define FBINFO_STATE_SUSPENDED 1
4 S. u7 V9 p* b3 S" k0 o: b; fu32 state; /* Hardware state i.e suspend */+ ~& y8 J+ {8 R" H' G
void *fbcon_par; /* fbcon use-only private area */) v2 A6 @- B+ F( L
/* From here on everything is device dependent */
7 X0 P4 S3 Y7 Q Avoid *par; /* 这个用来存放私有数据 */1 o/ A7 o. N" {
};6 ^# O. v# w' }
- o7 f1 p3 e( u. Y
2.fb_ops结构体(在include/linux/fb.h文件里定义)! z" N# _0 r2 n+ Y/ u9 f, d
3 x' t8 L6 r( h, E! ~8 W考虑到fb_ops结构体里面的函数指针成员太多,这里仅简单列举几个比较常见的,具体的请参考源代码。" D: t; P6 X7 ]/ f( S" {! Z
$ d; k4 m' n4 K3 T1 h, }/ c
struct fb_ops{$ M' j1 D* v- n9 p
struct module *owner; /* 模块计数 */
9 S2 Q# o2 O* U K$ k" J1 {int (*fb_open)(struct fb_info *info, int user); /* 打开函数,第一个参数为fb_info */
' m, [- l _+ X3 \/ aint (*fb_release)(struct fb_info *info, int user);2 k' w3 z$ ?( w1 v: B
。。。。。。
' x, C$ n+ `% J1 E/ S% V1 F/* fb_check_var函数用来检查可变参数,并调整修改可变参数 */
1 Z& J) u/ f: P' B2 L& uint (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); O5 ]6 C2 h+ f
。。。。。。
! w. V& Q& y3 ?8 A4 M; }/ Z/*fb_setcolreg函数就是用来设置fb_info里面的pseudo_palette调色板成员 */( ~- ?: ^3 Q" \$ J/ j
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
2 C7 A' p D8 d# [4 b unsigned blue, unsigned transp, struct fb_info *info);) { n7 k. G9 G/ j0 o& h3 v, p1 v% n1 k
。。。。。。
1 {9 E8 @! ~; H% ]5 N7 m; z" a! q% H; r1 e0 D
/* 下面三个是通用的函数 */
% [, {7 U( q0 V2 v' ^/* Draws a rectangle */' Z& b3 b7 ?2 O2 N' y7 k! ^
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
0 T8 g/ J+ j7 O+ V4 ~8 b/* Copy data from area to another */. m4 Z* W+ X8 D2 N3 G
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
& A$ I, O8 ^0 [- d/* Draws a image to the display */
9 D e$ _8 Y4 s' y6 S$ P, Cvoid (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
7 }" }6 c7 H: `2 p6 g9 z f w。。。。。。
r! r3 Q6 x! H5 `/* 有了fb_ioctl应用层可以通过ioctl系统调用来设置屏幕参数等 */
; |/ ^; H, C" e- ? h; tint (*fb_ioctl)(struct fb_info *info, unsigned int cmd,7 u; c# i$ Q& ?5 a* D/ _1 x7 j2 v
unsigned long arg);8 F+ M0 V: f1 s$ @. b* ?5 n& p7 W9 h7 J+ _6 e
。。。。。。
& f; W" F5 n: q6 W6 Z- |7 }/* 有了fb_mmap应用层可以通过mmap系统调用来读写帧缓冲区内存 */1 K t: w1 B8 n5 }* E, j8 F
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);' R6 b+ Q/ y/ Z
。。。' F8 _/ ~+ w- F7 e7 r9 M- @ o$ S
}; R; d3 A5 A) A. E: E
. \. L, r: Q# ^# O3 k( ?, q
3.fb_var_screeninfo 结构体(在include/linux/fb.h文件里定义)
: j) s3 W) }+ D# B- w
' E* D# ~# s9 @fb_var_screeninfo 被fb_info结构体所包含,这个结构体主要用来设置LCD屏幕的参数,如分辨率、像素比特数等,LCD驱动程序里面硬件相关的设置很多都涉及这个结构体。
. `/ \) \& U: g; c5 J) w A
b( c( J, d( G. B) Ystruct fb_var_screeninfo {! ?1 {! F% c1 M( \+ D" p
__u32 xres;/* visible resolution,分辨率,即一行有多少个点 */1 X, u% B" z5 m( E8 t v
__u32 yres;
; l/ l. [; t# I1 \) s__u32 xres_virtual;/* virtual resolution*/0 {. @% k: I s( W1 k! |8 K( l
__u32 yres_virtual;
$ n9 P w8 u$ n! O__u32 xoffset;/* offset from virtual to visible */
$ F5 d! |4 U% A) D! k) X, D__u32 yoffset;/* resolution*/
. R8 l7 r" ~; d- ~/ B6 g+ X! U$ d J1 \8 N" O& T
3 l6 C X5 [$ |' P4 u9 T: f
__u32 bits_per_pixel;/* guess what,定义每个点用多少个自己表示 */! z. O4 y+ X1 [- X3 S
__u32 grayscale;/* != 0 Graylevels instead of colors */
" z% T/ A$ F# b7 l6 ?* W* d
$ F/ ~7 B0 r, w$ v6 W' I3 J
7 V z1 B+ c. L/ T3 o$ cstruct fb_bitfield red; /* bitfield in fb mem if true color, */2 c. e3 m. ~ e1 o& D, n
struct fb_bitfield green; /* else only length is significant */5 e8 u+ f" s' N3 t
struct fb_bitfield blue;
" c+ ?2 d) c+ ^* M4 X$ h1 M) S, u& qstruct fb_bitfield transp; /* transparency*/8 b- f0 F3 i. y: e" H5 \
! ]' C O& Y' V
' {" V2 {, n, K1 }2 @) Q! x__u32 nonstd; /* != 0 Non standard pixel format */3 g6 V3 b$ h) p$ R
, X. y! l1 W! g2 b; x3 C
8 }- F6 o9 H5 w2 }, ~
__u32 activate;/* see FB_ACTIVATE_**/
+ |! Z' o4 \# K* r# p8 k0 A, B1 J/ w: t+ w% `
+ A( l6 B" E2 N6 e4 E2 y- j__u32 height;/* height of picture in mm */: \) W9 a4 W3 p3 u& M9 g
__u32 width;/* width of picture in mm */7 E' D) T! T( Q2 X% v5 {. p2 z1 e
. {! Q9 x! B& U% N, d2 N: r5 X+ A4 X6 g, _; {
__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */
* g$ @7 D6 P, s, B- @ r
* b J' o y6 |- q* e
4 m; P! D1 c2 J# [/* Timing: All values in pixclocks, except pixclock (of course) *// j6 ~/ p3 V5 @, _5 ~: w
__u32 pixclock;/* pixel clock in ps (pico seconds) */9 ]" M: ]$ i& Z5 j+ x4 Q
__u32 left_margin;/* time from sync to picture*/
" L! }" \. o6 I/ i" b2 ~/ }$ Y__u32 right_margin;/* time from picture to sync*/
" x' k4 M g0 n) }. I- ]4 H0 Q8 j" r__u32 upper_margin;/* time from sync to picture*/7 Y: L' w2 W* h! I
__u32 lower_margin;
7 x( k1 C8 F7 N9 }7 M__u32 hsync_len;/* length of horizontal sync*/
6 G9 G' M. } y* Z__u32 vsync_len;/* length of vertical sync*/
' n* \2 n6 ^' R__u32 sync; /* see FB_SYNC_* */1 h* x, g. a5 i4 B4 w/ N- u1 d
__u32 vmode; /* see FB_VMODE_* */) K9 r* C; S4 ~( z1 g
__u32 rotate; /* angle we rotate counter clockwise */
* M ~5 c% B2 [9 F- W, E__u32 reserved[5];/* Reserved for future compatibility */
& l9 V% f; s: |4 N8 @4 ?- h% A};
: Z# d/ T$ S: ^- { |" f `! H$ y# R% t+ w$ l% j" P
4.fb_fix_screeninfo 结构体(在include/linux/fb.h文件里定义)
8 f5 s) f+ \8 t+ Y+ N, k9 N
3 _+ X6 |7 D5 I% astruct fb_fix_screeninfo {
$ [& T6 g8 Y: x+ F# w3 f/ w6 Gchar id[16];/* 驱动名字就保存在这里*/7 @6 d7 j c# _1 {/ p; {# L, o
unsigned long smem_start; /* fb缓冲区的基地址,这是一个物理地址 */" S" A% `, l* }1 W- {- z; c6 o' y
__u32 smem_len; /* fb缓冲区的长度 */; K6 t9 ~4 G8 Q6 I* y- L6 c
__u32 type; /* FB_TYPE_类型*/
2 J( |' u) O- f__u32 type_aux;/* Interleave for interleaved Planes */( j% J6 R/ A) \: y% ^5 F
__u32 visual;/* FB_VISUAL_类型*/ , ^: J" j6 r/ H+ e1 |
__u16 xpanstep;/* 一般设置为0 */
3 a+ w9 A( @# ?1 r( E }. \ Y% K/ [__u16 ypanstep;/* 一般设置为0 */# S( N4 S1 s+ a4 ?
__u16 ywrapstep;/* 一般设置为0 */2 G% q+ y* D# j8 H8 ^" p1 {9 i! ?
__u32 line_length;/* 屏幕一行有多个字节 */
& c. |1 l3 @5 k9 vunsigned long mmio_start;/* Start of Memory Mapped I/O */
# t1 g$ J% P# x4 m$ y/ _2 A4 ^9 V/* (physical address) */
$ i! \4 X) ^& M1 R2 m3 h__u32 mmio_len;/* Length of Memory Mapped I/O */
" E4 ~8 Q+ a1 D) l- W0 f9 t! A__u32 accel; /* Indicate to driver which */
2 g$ X; U: k- [/* specific chip/card we have*/4 @ k$ H; [/ @, o8 x% b" c
__u16 reserved[3];/* Reserved for future compatibility */
% @. B. L9 _; O- _6 \' I4 g};
6 G _- A/ l( w1 g& p9 H0 q
2 l4 d; U) r, a5 ]以上笼统的介绍了几个重要的结构体,大家如果没有阅读过源码的可能对这些结构体比较陌生,但是没关系,比较常用的我都用显眼的颜色标记了,大家结合以后的博客日志就会懂这些结构有什么作用了。
9 o' H ?5 ~' g
7 W- X5 C2 `6 u5 d对于这些参数会在哪里设置?通过什么样的形式来设置?% S/ R$ [6 `' f) Z/ M! h0 |
- G C$ W8 Q3 K6 D H, p' @1 C4 C答:通过平台设备的方式来设置,这就是鼎鼎有名的platform_device结构体了,这个知识留到后面的LCD驱动篇来讲解。: @5 C! V0 `6 B
( a# Z$ T Z: @1 M
; A+ ?" @) c9 b2 e4 d1 X
! K& L2 S5 Q% a |
|