|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
貌似好久好久没写驱动类的博客,距上一次写驱动的博客还得回到半年前,那时天气还很冷,如今已经热的要命,但我还是想把自己学习到的知识跟大家分享。没写驱动类的博客是觉得Linux下的驱动源码真是太多太多了,半年前我也比较害怕Linux源代码,随时时间的推移,自己琢磨了不短时间了,觉得大概能读懂Linux源代码了,也就没那么害怕它了。
o& F! `9 z4 h1 C# H
* i( h+ ]* R8 Z, r4 o9 w3 P原归正传,预定以后的驱动博客我想用尽量短篇幅来记录,但是会以尽量详细的角度去分析驱动。学习驱动心得,驱动呢主要还是要抓住主干的架构,太细节的东西不必太刻意去研究,因为很多太底层的函数人家已经帮你实现了,你不必去怀疑它正确与否。
; o! p' }; v: y" [- O( V
* K/ n5 k- g! vLCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作。用户根本不用关心物理显示缓冲区的具体位置及存放方式,因为这些都由缓冲区设备驱动完成了。
, e9 v- {! ?, z4 x X
% O! W$ o4 y& L启动开发板后执行ls /dev/fb* 命令可以看到,帧缓冲设备的主设备号为29,对应/dev/fbn设备文件,一般为/dev/fb00 n$ {( I' n2 M% M' y* t( P
+ |. `( w+ c5 y6 F8 l在弄清楚LCD驱动架构之前,我们先弄清楚几个重要的结构体,为了减短篇幅,有一些不是很重要的成员会用省略,具体的源代码请大家参考Linux源代码,这里我使用的源代码是天嵌公司提供的移植好的Linux-2.6.30.4。5 Z1 w& Y A/ i4 T3 U
/ O" ~1 z a. [# e" ^- O
1.fb_info结构体(在include/linux/fb.h文件里定义)1 A# Z Q+ \5 k5 L$ I
* F# \; N/ T0 o! U" `" m6 r
struct fb_info {. q5 `1 w8 E) d- Y: F
int node; /* 序号索引值,/dev/fb0,/dev/fb1 其中0,1 就是从这里获得的*/' K. x' a6 B3 _6 i. I. L
int flags;
. `/ `& o; s; }$ k. T& r+ ystruct mutex lock;/* 一般在 open/release/ioctl 函数里会用到的锁 */5 b- @9 p% y! q6 G! G0 D
struct fb_var_screeninfo var;/* 可变参数,很重要 */
- N' y/ S' l, F! C6 @$ I( [struct fb_fix_screeninfo fix; /* 固定参数,很重要 */; I3 T7 ]! M0 ^$ F+ g; |
struct fb_monspecs monspecs;/* Current Monitor specs */6 d5 _1 O: d% W& s" e
struct work_struct queue; /* Framebuffer event queue */
! B9 O' k/ m2 v/ [4 F3 y7 W0 wstruct fb_pixmap pixmap; /* Image hardware mapper */" W# t3 F, D8 O( n
struct fb_pixmap sprite; /* Cursor hardware mapper */
2 l9 O# @8 W! f. t1 a4 L+ Xstruct fb_cmap cmap; /* Current cmap */ S5 x- [! Q }& s+ K2 E
struct list_head modelist; /* mode list */' n. j. w* I6 d
struct fb_videomode *mode;/* current mode */" J" B q2 Q# z! j: J. r X; X" b
5 U+ }& B4 u U2 l) f+ P。。。。。。/ \: I5 s% s2 H( |: Z$ g( { f2 @7 {$ I
/ m) k( `1 W; E" @struct fb_ops *fbops;
. z: o/ B( O7 N, D1 Wstruct device *device;/* This is the parent */
1 B" j4 p: i7 Tstruct device *dev;/* This is this fb device */
) [! y+ J/ e* n
/ h" }& L" k+ M' f4 C u' C0 Q。。。。。。& {3 b+ z8 x6 P: u! }2 b
char __iomem *screen_base;/* "显存“的基地址 */
2 D$ X& S/ H k; I0 kunsigned long screen_size; /* ”显存“的大小 */
5 A) T0 O. `1 C, _void *pseudo_palette; /* 16位假的调色板 */
0 A3 _) H3 P! C) ~* d6 ~9 M2 ?#define FBINFO_STATE_RUNNING 0
3 t: K7 n$ X7 g; I) j4 |#define FBINFO_STATE_SUSPENDED 1
6 L2 M9 D0 \" q3 O2 I: s! {5 l) f0 Bu32 state; /* Hardware state i.e suspend */
- A1 s* j4 e) ~+ svoid *fbcon_par; /* fbcon use-only private area */
* b. c$ `6 e. V% F7 m" u' O/* From here on everything is device dependent */
1 x) ^8 [2 @( H$ l6 ?; F# |void *par; /* 这个用来存放私有数据 */) c+ Z3 _# J8 h3 Q; c
};
8 m4 H9 z, b5 _! N
3 }6 U( l O0 Z1 D$ E2.fb_ops结构体(在include/linux/fb.h文件里定义)
3 q. z. d( j6 w! X4 c1 q1 o+ Z$ I0 |% `* i" P* G) h
考虑到fb_ops结构体里面的函数指针成员太多,这里仅简单列举几个比较常见的,具体的请参考源代码。
1 G( }, U9 h( r$ @- d5 }8 D1 J; t1 e; P# \
struct fb_ops{% h# h, O0 `7 ^) M
struct module *owner; /* 模块计数 */
4 t% f8 D' W5 \5 X3 ~+ ^/ sint (*fb_open)(struct fb_info *info, int user); /* 打开函数,第一个参数为fb_info */
5 n7 l0 C9 v8 l- z3 F8 vint (*fb_release)(struct fb_info *info, int user);
0 c, C/ u6 Z6 J. N。。。。。。4 B" U7 x5 [1 a2 H- r
/* fb_check_var函数用来检查可变参数,并调整修改可变参数 */' p5 l: J Y* z* m9 ^8 N
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);6 P5 }/ ~4 O5 Y# R: M9 `( r
。。。。。。; J0 X& ~: x/ [% D
/*fb_setcolreg函数就是用来设置fb_info里面的pseudo_palette调色板成员 */1 ^2 O8 A: d8 g5 b2 G3 o4 ]: q
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
. c& r5 P: i( ]4 g; P unsigned blue, unsigned transp, struct fb_info *info);6 l C/ ~3 r3 M. n' F: f
。。。。。。( |% S- \$ r# C4 j
6 R6 V' H. c. D! R( J( B
/* 下面三个是通用的函数 */
" E0 I- k/ A2 j w& M6 a+ k/* Draws a rectangle */5 ]# r4 L- E+ b# K8 f
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
: F9 N" A2 S" X' O8 i; W9 R5 s/* Copy data from area to another */# k' @. R. P- m+ ^ Z1 O9 ]& l
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
: O3 C. r9 V* v8 u2 l7 E B/* Draws a image to the display */
5 l5 ]7 Z/ S# D/ v* q' Zvoid (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);0 I7 ^. p( W3 B% K& a( g' ^
。。。。。。9 w& M/ {$ }1 B! e
/* 有了fb_ioctl应用层可以通过ioctl系统调用来设置屏幕参数等 */
/ u; e9 Z$ X) T5 C: z; K, ^. n: zint (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
* @1 I; R$ i( I9 ounsigned long arg);
& |+ h3 @: V; V% _。。。。。。3 [8 v) N% x# V1 m& J e
/* 有了fb_mmap应用层可以通过mmap系统调用来读写帧缓冲区内存 */
7 a' U8 S l: e, y8 B9 uint (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
/ b" C: K& f- J2 A5 q。。。" e9 b+ o, c- Q- W# N6 E
};
- b9 t& q+ @, _- t+ {; I- s6 ~0 U( O( {+ w0 S
3.fb_var_screeninfo 结构体(在include/linux/fb.h文件里定义)8 _. s; y+ b% T
* _8 h/ I/ `0 N& f% jfb_var_screeninfo 被fb_info结构体所包含,这个结构体主要用来设置LCD屏幕的参数,如分辨率、像素比特数等,LCD驱动程序里面硬件相关的设置很多都涉及这个结构体。& f' ] p6 ~& j" L1 [3 X& ]
. m4 a$ w; |7 M: D$ j8 ^struct fb_var_screeninfo {# C3 Y: Q; w; E
__u32 xres;/* visible resolution,分辨率,即一行有多少个点 */
' X. w- X) {; W3 E7 _+ J+ x+ t__u32 yres;
; N* n4 }6 n/ z3 w# I__u32 xres_virtual;/* virtual resolution*/
5 w% Y4 o/ ~1 k$ v; l: v& m+ b__u32 yres_virtual;+ Z6 q; |1 G( M Q7 K
__u32 xoffset;/* offset from virtual to visible */5 T$ x: g" I/ C5 X
__u32 yoffset;/* resolution*/
# E9 @+ d9 |# B: V: H
6 Z4 h V0 \$ b8 E/ M4 G1 e
/ o7 t+ J( q6 M4 t6 i__u32 bits_per_pixel;/* guess what,定义每个点用多少个自己表示 */
* p0 E9 h- S f+ `& I__u32 grayscale;/* != 0 Graylevels instead of colors */2 L0 j g7 j6 j+ V
. y* r) b3 D- I) E8 u9 n) M) Z
/ y. I+ }+ ?% d6 d1 U( w% Q5 W
struct fb_bitfield red; /* bitfield in fb mem if true color, */1 l$ p4 o2 ~* B+ x
struct fb_bitfield green; /* else only length is significant */
6 T/ ^( W' d4 y H9 o5 i0 w! dstruct fb_bitfield blue;, P3 ~! o# q4 Z3 M
struct fb_bitfield transp; /* transparency*/1 v0 A8 U/ [( }- M! P- R
- T6 A+ {5 g# J2 X/ f( ]6 N
( d2 D+ W' a+ a$ }9 F! a
__u32 nonstd; /* != 0 Non standard pixel format *// V* P9 O' `/ S6 ?! z3 V4 e( r6 S6 }
( h3 f+ `3 D& I ?. O9 I/ r
& D9 Q' h& }; L: X8 e9 q" V) M: a__u32 activate;/* see FB_ACTIVATE_**/# R9 k: b5 E" }. y, D
6 i, b; e M; L
7 }; Q) P: T, f+ q. Q( L__u32 height;/* height of picture in mm */) e F8 L% p$ w# Z. D s/ M
__u32 width;/* width of picture in mm */" q: G' O+ q- ~+ l
- F6 I* P: i: w. l% Q) I
5 g) P, T( Q r' z( D__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */3 m, z+ C& Z N7 x: t& }! y
; s# j3 O2 }( ?9 A3 h
4 o% D2 d1 q. g, h; l
/* Timing: All values in pixclocks, except pixclock (of course) */
0 R3 n2 A [1 {( A, f3 ~3 X6 r__u32 pixclock;/* pixel clock in ps (pico seconds) */
" U6 [1 C8 I' l% Q4 \' P [/ N N__u32 left_margin;/* time from sync to picture*/
# k1 @6 K9 V1 F5 A. l* ]__u32 right_margin;/* time from picture to sync*/
1 s; j# @9 C4 W* z0 ~" f__u32 upper_margin;/* time from sync to picture*/' {- h& T/ C; t$ m6 {
__u32 lower_margin;
1 e2 z; x+ @2 h__u32 hsync_len;/* length of horizontal sync*/# Q6 F4 b4 {5 S: L
__u32 vsync_len;/* length of vertical sync*/! i$ d0 y [* z/ e7 e' v) f: A+ T
__u32 sync; /* see FB_SYNC_* */
8 h' H, h' }0 D7 B+ F \__u32 vmode; /* see FB_VMODE_* */
% b7 t M7 e' F, s, {2 a__u32 rotate; /* angle we rotate counter clockwise */
, a6 F' a( v( r8 c" d( Y) p5 Q0 X__u32 reserved[5];/* Reserved for future compatibility */
" P% p9 R& M) b! F( j9 p};
8 h% a! n! B8 W* L
) N# ]. k4 E3 s2 \4.fb_fix_screeninfo 结构体(在include/linux/fb.h文件里定义)7 P5 X; v) V! \0 R7 o/ H
; ~0 A t i9 R' G0 } ~struct fb_fix_screeninfo {/ O# d( @5 C- [5 m
char id[16];/* 驱动名字就保存在这里*/% B" `* u% l# ?9 ?% q' j1 M3 s
unsigned long smem_start; /* fb缓冲区的基地址,这是一个物理地址 */& Y7 u6 o1 W7 o$ s
__u32 smem_len; /* fb缓冲区的长度 */
0 {: J5 u8 H8 f; G! T__u32 type; /* FB_TYPE_类型*/
$ U/ `' A" w& ___u32 type_aux;/* Interleave for interleaved Planes */
x( e9 T# ]. Y1 k( J__u32 visual;/* FB_VISUAL_类型*/ 9 k s& H7 z! `# ]9 x9 t( h; E R
__u16 xpanstep;/* 一般设置为0 */
3 t0 {0 ?* X$ G" B1 X__u16 ypanstep;/* 一般设置为0 */$ R+ d- j3 h4 [$ e& a
__u16 ywrapstep;/* 一般设置为0 */$ q# } h* k' V: P+ n. p; N
__u32 line_length;/* 屏幕一行有多个字节 */5 h$ S2 P5 X( z% i0 m- L6 {
unsigned long mmio_start;/* Start of Memory Mapped I/O */" J8 `$ e" W4 p6 ]8 D* H
/* (physical address) */& E: R+ i3 L8 V ~# c" @
__u32 mmio_len;/* Length of Memory Mapped I/O */
i5 O# {5 a# p; x, o7 f+ Q__u32 accel; /* Indicate to driver which */0 W K! k: X: d/ {& v- f
/* specific chip/card we have*/" M" n0 b3 w) m; w
__u16 reserved[3];/* Reserved for future compatibility */
2 M. l. K* r9 @$ j};0 [; a2 Y0 B6 Z
& L4 g8 ~: h0 D
以上笼统的介绍了几个重要的结构体,大家如果没有阅读过源码的可能对这些结构体比较陌生,但是没关系,比较常用的我都用显眼的颜色标记了,大家结合以后的博客日志就会懂这些结构有什么作用了。' Y. T- H* z4 X+ E& ?% y i2 v! \
* Q u: k8 }5 v8 a( [9 m
对于这些参数会在哪里设置?通过什么样的形式来设置?+ h$ m9 q' Y" C! L0 b ~
0 Z+ O3 f% F) D3 S8 L
答:通过平台设备的方式来设置,这就是鼎鼎有名的platform_device结构体了,这个知识留到后面的LCD驱动篇来讲解。
* B: a' s9 F. @9 k- x( _, |" }! P! x% Y' i7 O e3 }/ n
1 F- `4 A* h. G3 c# s" r- L$ J' m0 J( E) F" {, I# W
|
|