|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
貌似好久好久没写驱动类的博客,距上一次写驱动的博客还得回到半年前,那时天气还很冷,如今已经热的要命,但我还是想把自己学习到的知识跟大家分享。没写驱动类的博客是觉得Linux下的驱动源码真是太多太多了,半年前我也比较害怕Linux源代码,随时时间的推移,自己琢磨了不短时间了,觉得大概能读懂Linux源代码了,也就没那么害怕它了。# _: |* G: N9 e$ }3 T/ M
) |9 L- v) L8 Y7 s5 Z
原归正传,预定以后的驱动博客我想用尽量短篇幅来记录,但是会以尽量详细的角度去分析驱动。学习驱动心得,驱动呢主要还是要抓住主干的架构,太细节的东西不必太刻意去研究,因为很多太底层的函数人家已经帮你实现了,你不必去怀疑它正确与否。
' r5 E, }" X5 L/ N* _" M& R0 X; v8 w3 \4 Q8 E, X$ H6 `
LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作。用户根本不用关心物理显示缓冲区的具体位置及存放方式,因为这些都由缓冲区设备驱动完成了。2 V" X+ g v/ G3 @
: @0 T7 ^2 A2 k2 D+ M/ i5 x
启动开发板后执行ls /dev/fb* 命令可以看到,帧缓冲设备的主设备号为29,对应/dev/fbn设备文件,一般为/dev/fb04 C$ {& R% Q) l+ y' w U j
/ L: ^& t) u- |4 ^! h, H在弄清楚LCD驱动架构之前,我们先弄清楚几个重要的结构体,为了减短篇幅,有一些不是很重要的成员会用省略,具体的源代码请大家参考Linux源代码,这里我使用的源代码是天嵌公司提供的移植好的Linux-2.6.30.4。
( a3 P. M* S: M' C& w5 {! W1 i+ r1 J3 n- a3 `5 d0 ^3 [
1.fb_info结构体(在include/linux/fb.h文件里定义)9 g6 i" I3 z7 h8 k1 H9 h6 `! K0 L9 }
3 E; Y! O3 D7 q$ y3 z
struct fb_info {6 r5 E' P( N, o* x/ y
int node; /* 序号索引值,/dev/fb0,/dev/fb1 其中0,1 就是从这里获得的*/
; y9 L0 L3 V0 a' nint flags;
7 a7 e' w- M9 ]! i5 [struct mutex lock;/* 一般在 open/release/ioctl 函数里会用到的锁 */
# y2 ?' [+ f- O9 o' }2 Ostruct fb_var_screeninfo var;/* 可变参数,很重要 */: F- H6 d3 R; b4 N! b" C
struct fb_fix_screeninfo fix; /* 固定参数,很重要 */
K" ^0 B/ {6 x. n" s6 h7 sstruct fb_monspecs monspecs;/* Current Monitor specs */
1 `5 @' S% v- ystruct work_struct queue; /* Framebuffer event queue */! {/ D3 A( Q* y; y! ?, Y- }* Q" y
struct fb_pixmap pixmap; /* Image hardware mapper */) u8 O$ U& V u
struct fb_pixmap sprite; /* Cursor hardware mapper */& W; M( T L2 F; f8 y( w
struct fb_cmap cmap; /* Current cmap */
7 T3 ^! U8 [, S6 I7 f# Rstruct list_head modelist; /* mode list */
( r# q/ |0 f1 ]% dstruct fb_videomode *mode;/* current mode */
2 i+ t+ |6 S3 D, q; W2 S! S' j; w U: O: c A
。。。。。。
+ e, H& {8 [4 j- _; b8 T' u6 y3 \1 P$ |
struct fb_ops *fbops;
z; t. {2 S L0 R: Fstruct device *device;/* This is the parent */
( E# P% `" t ~+ y1 w' Ustruct device *dev;/* This is this fb device */! C' g+ r: D2 \& z0 B) S9 l
0 K. z7 [: M; Y" ~) S
。。。。。。8 m {& ]- t/ F, k K) w" N! i
char __iomem *screen_base;/* "显存“的基地址 */& W- O( Q" Z# i; A
unsigned long screen_size; /* ”显存“的大小 */
" T U6 D/ |! avoid *pseudo_palette; /* 16位假的调色板 */
/ a1 A5 R ~% x#define FBINFO_STATE_RUNNING 0% k' y' J' o" c# N: Z0 B
#define FBINFO_STATE_SUSPENDED 1# i" o/ R$ [- o/ A
u32 state; /* Hardware state i.e suspend */ t+ Q& I; _6 b6 M0 ]* M
void *fbcon_par; /* fbcon use-only private area */
9 i; |) p6 m W! p! o) m. X/* From here on everything is device dependent */" `5 Z& x6 i9 j1 j% {
void *par; /* 这个用来存放私有数据 */. h9 V) Z. g( M3 a( @0 m
};. x7 C Q, W; n
$ T' f K: p; g
2.fb_ops结构体(在include/linux/fb.h文件里定义)
* e. ~ p7 Y2 v! u( N% ?' r7 p2 ]! U4 D" n( w4 u
考虑到fb_ops结构体里面的函数指针成员太多,这里仅简单列举几个比较常见的,具体的请参考源代码。; _3 X7 [" `) y2 _* g5 L0 b: Q) V
8 H0 i" L1 `; E5 w: O% c2 o
struct fb_ops{3 a, A3 h4 x2 \- ~. `
struct module *owner; /* 模块计数 */, u8 ~; ?' b" i) V* c) G1 x
int (*fb_open)(struct fb_info *info, int user); /* 打开函数,第一个参数为fb_info */
% m7 h: K& x0 D' V+ q' cint (*fb_release)(struct fb_info *info, int user);
" W2 y! N* j G。。。。。。$ V; C, K8 k. `& i0 h
/* fb_check_var函数用来检查可变参数,并调整修改可变参数 */
% H: W' }3 R% r! g- w9 `int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
( Y2 t% J+ q0 i" Q。。。。。。
# ?1 c8 u6 v1 ?, T0 d& T# U3 ?/*fb_setcolreg函数就是用来设置fb_info里面的pseudo_palette调色板成员 */
4 \' C/ J, Z. a6 R+ K1 Qint (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,9 r7 n1 S2 a+ f
unsigned blue, unsigned transp, struct fb_info *info);- k! D! [) ~) g* x( L- @
。。。。。。2 [4 l: z# Y6 N5 u, {
9 n& m5 n* N. b0 \0 _& b( B; c/* 下面三个是通用的函数 */
7 r! ~1 [0 A% T& @0 u/* Draws a rectangle */& Z4 f! ` X! ]. B$ y: _& b9 V% F
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);" H8 L8 \8 ]$ p2 i
/* Copy data from area to another */7 Q( x, U8 ]6 K
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);! B1 i: r& ?( c2 h
/* Draws a image to the display */" F, t& J5 J- l. p) \
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);2 f U0 K# s# N6 `
。。。。。。
; [( X. u) J. x3 v3 ]4 ^6 g/* 有了fb_ioctl应用层可以通过ioctl系统调用来设置屏幕参数等 *// i' G' X3 `1 l5 l8 O' F0 w0 E
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
$ Y% }$ f9 p) F1 Z* c8 Z! zunsigned long arg);
" S* r# b! g$ F。。。。。。* p/ ^2 h' i0 Q" v0 ]
/* 有了fb_mmap应用层可以通过mmap系统调用来读写帧缓冲区内存 */. X9 ^1 L/ f* Z% k5 Y( S$ B5 C
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);1 _) ]. X# Y( {5 ?1 A1 I4 Q
。。。
3 F3 H c# ^; t1 @2 o};
6 [( ^% B \" D# Y7 ^% B: K9 a( o7 U
3.fb_var_screeninfo 结构体(在include/linux/fb.h文件里定义)% d* N- K. u3 F* u" k
& _# o& X. [, j; K. v2 ]* dfb_var_screeninfo 被fb_info结构体所包含,这个结构体主要用来设置LCD屏幕的参数,如分辨率、像素比特数等,LCD驱动程序里面硬件相关的设置很多都涉及这个结构体。
' B4 J P' A: D+ M5 x9 q* C
& i+ r$ {$ ?9 s3 i# @/ gstruct fb_var_screeninfo {
+ M& M5 r' {# G) L8 U2 F__u32 xres;/* visible resolution,分辨率,即一行有多少个点 */. }( C& G) b8 `$ I3 B9 J0 u; G8 h( B
__u32 yres;
- O9 v# ]1 Z- t0 g8 P4 ___u32 xres_virtual;/* virtual resolution*/$ Y3 [# t" ?5 s' `5 h
__u32 yres_virtual;
( A" V S3 r" O, ^0 l1 r% @__u32 xoffset;/* offset from virtual to visible */- u! n; f& s1 Y, d
__u32 yoffset;/* resolution*/- y3 @5 w2 e8 E( c, }: }
$ `% u; ?- X3 X2 v% `
+ q1 e# |- o+ @. q__u32 bits_per_pixel;/* guess what,定义每个点用多少个自己表示 */
: g* ^3 g: @& U5 }__u32 grayscale;/* != 0 Graylevels instead of colors */
0 e$ w+ X8 c' G, G# n3 `# J2 n5 X
( g- b( G$ H1 z; K& [
struct fb_bitfield red; /* bitfield in fb mem if true color, */9 o1 H. ]8 R! A3 B+ b0 w% v
struct fb_bitfield green; /* else only length is significant */6 E. z/ ~( A' s/ b: Y7 G
struct fb_bitfield blue;$ `' ]4 j8 F- m2 l2 d' C( B
struct fb_bitfield transp; /* transparency*/
4 K: A1 O6 C0 q" [+ X' s) m- S h6 V
7 [: p& k `, p$ D8 P+ r% o/ m
! S/ l# B3 Q" t0 ^__u32 nonstd; /* != 0 Non standard pixel format */9 k( l" E3 j4 N, p: F
- K- l6 `. j9 ^2 V2 O' y8 H1 t2 j2 z! J! z; B
__u32 activate;/* see FB_ACTIVATE_**/
9 K' x* ~+ }/ A9 a- o6 `5 j
2 Y5 i" f& B; C" r. _% y6 o; T/ Z! O! R/ f
__u32 height;/* height of picture in mm */
7 i0 c, _3 c: \__u32 width;/* width of picture in mm */( u# B2 q3 }3 Y1 \5 }. e
/ M* w9 M9 I' m2 E% o9 }- E
* |3 w! J4 J9 Q: i- Q. b/ l__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */
' J, G- }* b# ]. T3 a4 D/ s8 r. N, g& _' `& t* f% E7 q
$ o/ j$ L% p ]/ T( b
/* Timing: All values in pixclocks, except pixclock (of course) */) _ i s! `9 {/ p: K* [9 Q
__u32 pixclock;/* pixel clock in ps (pico seconds) */$ ~' H f" t. s8 r: O: O; G
__u32 left_margin;/* time from sync to picture*/4 u( b6 Q2 _1 e: E) a& f
__u32 right_margin;/* time from picture to sync*/
* S5 x3 Q: l: n# M7 E0 R( L+ T& A__u32 upper_margin;/* time from sync to picture*/2 N4 b/ _* R v
__u32 lower_margin;
+ U0 {$ K8 D' r9 ___u32 hsync_len;/* length of horizontal sync*/- F) s# \& l2 e$ K
__u32 vsync_len;/* length of vertical sync*/- {* ], o) b8 \. L; D: H
__u32 sync; /* see FB_SYNC_* */
' `% V0 L, x: M__u32 vmode; /* see FB_VMODE_* */
: G1 D7 G/ s9 k" A' U__u32 rotate; /* angle we rotate counter clockwise *// E. s) Y% |& N2 c$ `- a: @, ^% W9 k& s
__u32 reserved[5];/* Reserved for future compatibility */4 o8 f% r# i; S8 f
};' s/ N2 e z5 J6 X- q5 \7 @# K
: j" `" d+ C: f; e3 X4.fb_fix_screeninfo 结构体(在include/linux/fb.h文件里定义)
* ?: q4 {6 [9 R P! S" M9 O) N% i) A8 X* v+ \; I
struct fb_fix_screeninfo {: s; ~2 k+ I/ X9 I1 C
char id[16];/* 驱动名字就保存在这里*/( h5 d7 N( L. \6 U( I: e
unsigned long smem_start; /* fb缓冲区的基地址,这是一个物理地址 */
' ^! T' N1 H4 K X+ s, N# H g/ f__u32 smem_len; /* fb缓冲区的长度 */
. [7 A1 }- }- ?5 D9 W8 D__u32 type; /* FB_TYPE_类型*/% v" b! F0 y& b* D1 o' S& Q O
__u32 type_aux;/* Interleave for interleaved Planes */% {# o2 ?1 |# d& C
__u32 visual;/* FB_VISUAL_类型*/
8 |0 M$ W p- Q. b__u16 xpanstep;/* 一般设置为0 */
8 E2 g4 R* P* ?__u16 ypanstep;/* 一般设置为0 */3 ^. A" i- E* k5 @8 t- a
__u16 ywrapstep;/* 一般设置为0 */
$ q: O3 k% `# s' { A5 J8 u' H/ J__u32 line_length;/* 屏幕一行有多个字节 */: n4 t3 I4 o2 U" R. A- ?
unsigned long mmio_start;/* Start of Memory Mapped I/O */
! m: H3 B+ A" H7 h# {3 r/* (physical address) */
' D( _3 j8 I4 R__u32 mmio_len;/* Length of Memory Mapped I/O */
$ d# d1 }' y+ ^1 r3 r- Y3 l* B. B8 r__u32 accel; /* Indicate to driver which */
}& P% c5 r0 [- S/* specific chip/card we have*/
9 F, ]- w4 C7 V5 w% g! Y2 |5 W__u16 reserved[3];/* Reserved for future compatibility */
3 B& [) e) R- } I1 b( ~};% d! |+ j. F! g9 ?- \$ ?+ l
7 [2 d5 S `- | g以上笼统的介绍了几个重要的结构体,大家如果没有阅读过源码的可能对这些结构体比较陌生,但是没关系,比较常用的我都用显眼的颜色标记了,大家结合以后的博客日志就会懂这些结构有什么作用了。
o# @6 ?; p7 O" y8 i I$ E4 H7 u: ~1 v) f% |2 a2 [: l- b
对于这些参数会在哪里设置?通过什么样的形式来设置?9 {; l' j7 U6 L: O+ W
r4 m1 J* H, L/ Y5 w- ? k# ]* g6 m答:通过平台设备的方式来设置,这就是鼎鼎有名的platform_device结构体了,这个知识留到后面的LCD驱动篇来讲解。; n$ g l/ f" W2 ~% [3 {. d
2 W7 ^7 G6 C6 K' [8 U) j. l& H' t( }4 U' X4 y3 q
- y# E8 v. |2 p3 g; } |
|