|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
貌似好久好久没写驱动类的博客,距上一次写驱动的博客还得回到半年前,那时天气还很冷,如今已经热的要命,但我还是想把自己学习到的知识跟大家分享。没写驱动类的博客是觉得Linux下的驱动源码真是太多太多了,半年前我也比较害怕Linux源代码,随时时间的推移,自己琢磨了不短时间了,觉得大概能读懂Linux源代码了,也就没那么害怕它了。
6 a+ j. b# c+ J8 K# A7 ~
5 O+ r! ~4 J' m1 o( x/ K V2 ]原归正传,预定以后的驱动博客我想用尽量短篇幅来记录,但是会以尽量详细的角度去分析驱动。学习驱动心得,驱动呢主要还是要抓住主干的架构,太细节的东西不必太刻意去研究,因为很多太底层的函数人家已经帮你实现了,你不必去怀疑它正确与否。
( \1 ]5 S+ ^: P* d2 V3 k" n% ?7 V
LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作。用户根本不用关心物理显示缓冲区的具体位置及存放方式,因为这些都由缓冲区设备驱动完成了。
) t/ h: O0 l; A- z
. S. h# v! T5 y, Z( \. P. Z启动开发板后执行ls /dev/fb* 命令可以看到,帧缓冲设备的主设备号为29,对应/dev/fbn设备文件,一般为/dev/fb0
; y' ~4 H: i& b3 w8 ]" X- f( v6 B1 g" W( a2 {- m, z
在弄清楚LCD驱动架构之前,我们先弄清楚几个重要的结构体,为了减短篇幅,有一些不是很重要的成员会用省略,具体的源代码请大家参考Linux源代码,这里我使用的源代码是天嵌公司提供的移植好的Linux-2.6.30.4。
- Y0 ^$ R7 v2 b4 b0 c. m3 P. D q- K8 I, g% Z1 U, j
1.fb_info结构体(在include/linux/fb.h文件里定义)
) f- H* M1 ^3 i |' c7 x5 O% ~% v# H- z
struct fb_info {
: f2 i4 ~# x0 S& D: x0 [int node; /* 序号索引值,/dev/fb0,/dev/fb1 其中0,1 就是从这里获得的*/
; z' ]7 Y3 s" M3 O9 r* Mint flags;
) M7 s$ Y7 x2 ~0 i! b' zstruct mutex lock;/* 一般在 open/release/ioctl 函数里会用到的锁 *// n. u) O/ `) Q/ p9 d/ E2 a
struct fb_var_screeninfo var;/* 可变参数,很重要 */5 [' T0 W4 F) ~4 i% m+ g) \
struct fb_fix_screeninfo fix; /* 固定参数,很重要 */2 G8 G- t( g0 L9 N9 N/ @7 V3 u \
struct fb_monspecs monspecs;/* Current Monitor specs */
2 R2 O3 @7 G' Kstruct work_struct queue; /* Framebuffer event queue */& A5 y$ c7 Z2 K. o
struct fb_pixmap pixmap; /* Image hardware mapper */
3 q+ U9 _" N: X+ \# R9 }struct fb_pixmap sprite; /* Cursor hardware mapper */( x3 l* D3 d/ \0 I- C
struct fb_cmap cmap; /* Current cmap */
7 |) ^! K: U% j9 O) vstruct list_head modelist; /* mode list */
; s1 X* r: i& A" ^2 X( l4 `struct fb_videomode *mode;/* current mode */; v$ @% n* a6 x) C# H
$ I' P$ j$ `9 i5 k* v, u, ?
。。。。。。
: J6 t- Y w. h0 X0 a( P( q( d7 x/ N1 R
struct fb_ops *fbops;/ B4 c1 p" [& O$ \+ d
struct device *device;/* This is the parent */% u: e0 q, z2 ?+ A4 c) T& y2 Y& E
struct device *dev;/* This is this fb device */
3 X5 A7 ]" g6 q( q# {7 ~9 Z
* I9 I( f: R/ {$ f。。。。。。' i2 ?/ t" N2 E0 \# ]1 U; |+ Y
char __iomem *screen_base;/* "显存“的基地址 */. Z0 A( g z( k
unsigned long screen_size; /* ”显存“的大小 */ * b5 f ^6 s8 z& M8 R
void *pseudo_palette; /* 16位假的调色板 */
! Q8 J% ?- _$ E9 H6 r, D#define FBINFO_STATE_RUNNING 0- a" i/ \- {, g* {; S- t& o% V! ?
#define FBINFO_STATE_SUSPENDED 1& h- }9 \4 p! }& S; c
u32 state; /* Hardware state i.e suspend */" I" t- Q) k/ _+ i: s
void *fbcon_par; /* fbcon use-only private area */0 I2 V3 `5 w z5 ^" M
/* From here on everything is device dependent */
/ O# j" Q1 F' }, z6 G- P# {void *par; /* 这个用来存放私有数据 */& w) Y7 M, l- W9 P% T L
};
! X: O. Z3 Q. d2 C! G- F
" M0 ~" E) T" f; R1 {0 [& k2.fb_ops结构体(在include/linux/fb.h文件里定义)0 C; d- s# E$ h. {% f
3 H3 m* y/ E9 z1 r% r
考虑到fb_ops结构体里面的函数指针成员太多,这里仅简单列举几个比较常见的,具体的请参考源代码。+ p. o5 y# ^% U4 d2 N0 y) j
$ d: Y* c$ c+ @3 T
struct fb_ops{
1 P1 _! D' w: K3 v" P/ Jstruct module *owner; /* 模块计数 */
B& M9 ?! @; K. Mint (*fb_open)(struct fb_info *info, int user); /* 打开函数,第一个参数为fb_info */$ S% \9 L% C+ c5 w7 k8 |
int (*fb_release)(struct fb_info *info, int user);) i' I1 g- k( o2 ~2 E" w( O
。。。。。。- g4 B% c+ {) A( {7 x: c# l8 W0 C
/* fb_check_var函数用来检查可变参数,并调整修改可变参数 */
8 U e! G, n; v2 ~) w1 ^int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);6 H3 @6 s1 S9 ` w1 P
。。。。。。
5 o1 }' j. l8 r+ |+ b: A7 U/*fb_setcolreg函数就是用来设置fb_info里面的pseudo_palette调色板成员 */" p5 s6 U& ?. ?! \. ?) R6 O m! R
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,9 G* }3 r2 v3 x/ L" j5 g3 ~" v
unsigned blue, unsigned transp, struct fb_info *info);& N! V/ _0 X6 s' b# [
。。。。。。
. I5 d. f; x% d, e6 L! |/ G9 ~9 j. I+ z# O" L: l! D& W/ Q+ D9 S9 @
/* 下面三个是通用的函数 */
, f+ x7 l" D' X& D/ S# U: ~/* Draws a rectangle */
; D7 z' ]" W% B; w1 ovoid (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
0 \1 K) P0 P$ K3 {5 S. A/* Copy data from area to another */ ^7 |( A9 L* V9 Q$ a6 O" A2 _
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);4 n0 P; ~( H' e* [
/* Draws a image to the display */ N# W0 e7 r% I, K- A
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
8 e1 f; L0 {) n% T8 A。。。。。。- H) O5 L0 R% k+ K8 j/ ?
/* 有了fb_ioctl应用层可以通过ioctl系统调用来设置屏幕参数等 */3 I: D7 V2 b3 u( W6 a8 p3 U
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
* v) B$ f! ?9 w5 A9 E- o& V% gunsigned long arg);
1 z) ~" q+ { N2 W& S+ T0 ~) C。。。。。。
, X, t3 S4 K/ n9 m7 @8 s/ }4 D/* 有了fb_mmap应用层可以通过mmap系统调用来读写帧缓冲区内存 */" m. g; t I8 H
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
, t& ?( w2 i4 }( U3 \。。。
8 O! T$ F5 m4 v3 z};
) A( R& C5 Q' c, D- G' V
" x p# Q$ Y8 d* u' ^3.fb_var_screeninfo 结构体(在include/linux/fb.h文件里定义)
. I3 I3 N y+ s, @# x4 w1 A! W, a7 k5 a( P; W
fb_var_screeninfo 被fb_info结构体所包含,这个结构体主要用来设置LCD屏幕的参数,如分辨率、像素比特数等,LCD驱动程序里面硬件相关的设置很多都涉及这个结构体。" p+ V) N8 ]# y& g$ d% e
/ J- ]" ^5 V2 z" Z+ h4 Mstruct fb_var_screeninfo {
$ D$ a6 {% i0 V; M- c; N$ m. Z4 u. U__u32 xres;/* visible resolution,分辨率,即一行有多少个点 */" x0 Q, e3 g9 q, u% v1 N
__u32 yres;
, c j/ L9 n, X5 T0 U# B2 o* c__u32 xres_virtual;/* virtual resolution*/
" A9 j8 T4 B8 _) n3 J& J4 Y! d__u32 yres_virtual;
# N8 a# ]* L: g. D__u32 xoffset;/* offset from virtual to visible */1 Z7 q1 ~4 t- t6 ^
__u32 yoffset;/* resolution*/
0 F- }5 R# A* ~" h$ _9 F! Q- I6 a
0 U D; |. L+ e9 Z
- g* f$ S' c" F% f# l8 b__u32 bits_per_pixel;/* guess what,定义每个点用多少个自己表示 */
1 q$ E% j! u) j6 v" R2 x# ^, }__u32 grayscale;/* != 0 Graylevels instead of colors */
# @; F T' I2 N4 q" R
) K* ?& D7 s+ y% g9 ]) K
# l' m! ^9 u) T0 A" M* S) _struct fb_bitfield red; /* bitfield in fb mem if true color, */- y4 k# B7 L3 v; F* Y: G: j
struct fb_bitfield green; /* else only length is significant */: d1 ^$ ]+ B9 U# C8 {5 s) `; K
struct fb_bitfield blue;' {$ T$ K' S7 \8 Q
struct fb_bitfield transp; /* transparency*/) _1 [% U, b' G, G0 Z) Q3 E
; U$ C1 T5 B8 ]* k% W% I$ f$ N4 z2 ?/ A& K; `5 J& q$ _5 P$ h
__u32 nonstd; /* != 0 Non standard pixel format */
9 w$ Q% I) R8 j3 ^9 ?6 b& H9 s$ V8 E1 q/ Y1 j
7 g2 X; K8 N8 |8 i$ R) Y) y__u32 activate;/* see FB_ACTIVATE_**/
( I# c( ?3 k, B/ L7 i0 ~! _! l# G" m7 m6 M+ O' T- m
5 p* |8 U8 u( L) J& |__u32 height;/* height of picture in mm */
. {: d. c2 |4 H0 u__u32 width;/* width of picture in mm */" h* ?2 W! ]2 @
- O) E4 w/ ]- S+ R! O, t! {' B& A3 l+ `4 v9 ]
__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */
. J! |5 w/ t6 j- `+ j& ^6 O
6 }$ w; q+ ?" u
) K7 _3 H0 H* [9 {3 U d0 [2 l/* Timing: All values in pixclocks, except pixclock (of course) */: j4 _% w9 n% @0 `! U& ^
__u32 pixclock;/* pixel clock in ps (pico seconds) */$ r9 v* @4 n1 B& q; x- E1 S6 h+ d
__u32 left_margin;/* time from sync to picture*/ ? ` c! J. l: N1 t6 L6 m
__u32 right_margin;/* time from picture to sync*/6 p/ @7 H' o' c" V' ]+ r
__u32 upper_margin;/* time from sync to picture*/+ J5 J5 o8 k/ S6 }; Q' a4 `
__u32 lower_margin;$ o }6 \) |0 r2 t: \$ `/ h
__u32 hsync_len;/* length of horizontal sync*/
k" E* S4 T4 i, D% O/ f8 t__u32 vsync_len;/* length of vertical sync*/1 i0 V& g' l8 H) H% A7 Y
__u32 sync; /* see FB_SYNC_* */) R/ j: B" y+ D) _
__u32 vmode; /* see FB_VMODE_* */
- q6 u+ \* Z, H! D__u32 rotate; /* angle we rotate counter clockwise */
- e3 t6 [- m6 N0 ?& h( Z1 e__u32 reserved[5];/* Reserved for future compatibility */
+ d" `6 m E( o9 c- P/ J};6 o4 x* I6 g) p- F# s8 d
- K9 ]+ f& S3 @. `& H9 g: N
4.fb_fix_screeninfo 结构体(在include/linux/fb.h文件里定义)7 ~4 j. e$ @9 Y( s- T' l6 [( B/ |
- ?5 n5 x4 v+ F; H# H1 K
struct fb_fix_screeninfo {
. y2 Q9 f' g- G, |! @char id[16];/* 驱动名字就保存在这里*/
9 r6 p5 m" ?& `unsigned long smem_start; /* fb缓冲区的基地址,这是一个物理地址 */% J- D1 v0 d% b! s$ `
__u32 smem_len; /* fb缓冲区的长度 */
! s& ^' [2 @* W3 i6 I__u32 type; /* FB_TYPE_类型*/
9 s! |& X- E. m8 n( P__u32 type_aux;/* Interleave for interleaved Planes */( Z) |# @% Q+ ]1 Q
__u32 visual;/* FB_VISUAL_类型*/ " M; _: ?- H( `! \9 ]
__u16 xpanstep;/* 一般设置为0 */8 ^, X) m/ s4 t" @, X+ `
__u16 ypanstep;/* 一般设置为0 */
1 o4 V) [% N3 V3 v. Z; q__u16 ywrapstep;/* 一般设置为0 */- b# q1 C' Z! B6 M
__u32 line_length;/* 屏幕一行有多个字节 */5 x3 H$ }/ u- s8 B: g6 Q# E
unsigned long mmio_start;/* Start of Memory Mapped I/O */3 m) }/ M4 j! V8 b
/* (physical address) */
; z2 V F/ [2 q- D8 M__u32 mmio_len;/* Length of Memory Mapped I/O */
# f# K7 Z! o5 G$ x, J2 `" p* q' z0 o__u32 accel; /* Indicate to driver which *// Z) |( |: t& U) O5 Z N
/* specific chip/card we have*/" j2 d- ~! Z0 {
__u16 reserved[3];/* Reserved for future compatibility */
# N+ @) J4 ^- o9 }8 _};
) r$ D A# K, |+ M0 X( o
( ]! l! G& R+ ~ T+ f, ]/ G& @以上笼统的介绍了几个重要的结构体,大家如果没有阅读过源码的可能对这些结构体比较陌生,但是没关系,比较常用的我都用显眼的颜色标记了,大家结合以后的博客日志就会懂这些结构有什么作用了。; z" P2 p. W( O+ g9 F" l
* b6 ^4 @' ?" I0 }6 y7 s
对于这些参数会在哪里设置?通过什么样的形式来设置?
; s, T9 `8 ?% z7 z# n' L- T( z) @4 c, A( f
答:通过平台设备的方式来设置,这就是鼎鼎有名的platform_device结构体了,这个知识留到后面的LCD驱动篇来讲解。2 Y: O! ?6 j- W+ ^( i1 P
( l( m0 |2 [+ [7 Y, r8 w& Q! N2 \' `$ z5 D
* E* Y3 D- ?- R) x7 Y3 ]7 ^
|
|