|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
貌似好久好久没写驱动类的博客,距上一次写驱动的博客还得回到半年前,那时天气还很冷,如今已经热的要命,但我还是想把自己学习到的知识跟大家分享。没写驱动类的博客是觉得Linux下的驱动源码真是太多太多了,半年前我也比较害怕Linux源代码,随时时间的推移,自己琢磨了不短时间了,觉得大概能读懂Linux源代码了,也就没那么害怕它了。
1 G, j" x: e0 c" F D4 S7 ]
# i4 H4 U% a8 `* [/ ]原归正传,预定以后的驱动博客我想用尽量短篇幅来记录,但是会以尽量详细的角度去分析驱动。学习驱动心得,驱动呢主要还是要抓住主干的架构,太细节的东西不必太刻意去研究,因为很多太底层的函数人家已经帮你实现了,你不必去怀疑它正确与否。
/ I# S4 K$ w3 S, E% X8 I" }( G6 P4 t$ H3 ^% D8 T
LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作。用户根本不用关心物理显示缓冲区的具体位置及存放方式,因为这些都由缓冲区设备驱动完成了。6 K) W$ T/ ~, t {; a
0 H% q8 {: Q* d, \" n启动开发板后执行ls /dev/fb* 命令可以看到,帧缓冲设备的主设备号为29,对应/dev/fbn设备文件,一般为/dev/fb0 O% \2 [! w0 F
4 l+ C* A5 ?' v4 J9 I; X在弄清楚LCD驱动架构之前,我们先弄清楚几个重要的结构体,为了减短篇幅,有一些不是很重要的成员会用省略,具体的源代码请大家参考Linux源代码,这里我使用的源代码是天嵌公司提供的移植好的Linux-2.6.30.4。2 Q5 x$ ?1 c$ Y9 Q& @& Q& c
" V, z. M# H8 E0 O
1.fb_info结构体(在include/linux/fb.h文件里定义)
, i% ]( G/ i+ r0 r+ b* Y
" ?. W. @: v E# y' ^- zstruct fb_info {
2 F# E* R( M2 j% Q8 J# Z0 uint node; /* 序号索引值,/dev/fb0,/dev/fb1 其中0,1 就是从这里获得的*/. B) T) ?# J6 \+ g2 r8 t* P2 u
int flags;2 m, V( m. l# e' g2 G
struct mutex lock;/* 一般在 open/release/ioctl 函数里会用到的锁 */% T( e- h3 p- i( ^: P6 d
struct fb_var_screeninfo var;/* 可变参数,很重要 */
# k4 f3 E3 j8 v5 ostruct fb_fix_screeninfo fix; /* 固定参数,很重要 */
$ ^0 |% n+ s. sstruct fb_monspecs monspecs;/* Current Monitor specs */$ ?' W3 t5 i+ I1 \5 h4 |
struct work_struct queue; /* Framebuffer event queue */; P R2 c8 G! [/ o/ b" k5 ~
struct fb_pixmap pixmap; /* Image hardware mapper */
, X3 {% Y: X5 t3 T9 ^struct fb_pixmap sprite; /* Cursor hardware mapper */, U0 N0 `: w' Z$ N& k) [: N
struct fb_cmap cmap; /* Current cmap */
5 { x4 U3 k9 c! z" D4 n2 cstruct list_head modelist; /* mode list */
|! ]* C* T9 C+ G3 C% H( N1 Nstruct fb_videomode *mode;/* current mode *// F& _: u( Y9 \
' ]9 k% u9 P# W+ o _5 k( n! V。。。。。。! L! J8 V' A I$ D
+ ~ n5 `/ N* p% F9 L$ q$ Z+ H+ i( Tstruct fb_ops *fbops;4 }: G9 u: w: Z) V
struct device *device;/* This is the parent */
/ I& b3 k) B6 Q; {struct device *dev;/* This is this fb device */
1 k2 F9 H! r D4 m- N# n
4 s' _5 ^! g8 S' A; R。。。。。。1 v' f8 b: F0 C$ y" v
char __iomem *screen_base;/* "显存“的基地址 */. t$ E0 D9 |6 v9 w0 l5 ]- A6 u& D3 A+ O
unsigned long screen_size; /* ”显存“的大小 */ % F0 A" c$ `* N' U" Y
void *pseudo_palette; /* 16位假的调色板 */ * H- L' T0 ]% j {* q% f0 B
#define FBINFO_STATE_RUNNING 0
' x! l7 u; x1 o, ~/ I/ W0 k& M#define FBINFO_STATE_SUSPENDED 1' \$ u ?) P- v0 p( l5 r
u32 state; /* Hardware state i.e suspend */
) V6 o2 J/ \/ W" t9 G8 cvoid *fbcon_par; /* fbcon use-only private area */
! G' v# O+ @( r8 i8 O9 G/* From here on everything is device dependent */
; G$ S f. Y* D X: @) Pvoid *par; /* 这个用来存放私有数据 */' A9 W7 W4 k0 u# q
};
* B% s6 C( m2 [9 ]2 R# M# g
9 [6 M+ s/ Z1 x3 u7 @+ I2.fb_ops结构体(在include/linux/fb.h文件里定义)5 t- X/ A! ^0 y
: I% l/ p$ M/ f2 b- ^2 R0 Z考虑到fb_ops结构体里面的函数指针成员太多,这里仅简单列举几个比较常见的,具体的请参考源代码。7 Y ?1 n6 ?% R/ [
7 I5 p. ` j: D: ^8 Qstruct fb_ops{! I. c# `8 b9 H3 j. K7 A9 i
struct module *owner; /* 模块计数 */
" G. z. z2 T7 Z# ]& d" A) \int (*fb_open)(struct fb_info *info, int user); /* 打开函数,第一个参数为fb_info */
9 ^0 p9 J/ f s, y6 _+ \" w1 hint (*fb_release)(struct fb_info *info, int user);
$ Z, ?" C8 o; h: Y9 O, B。。。。。。
# `4 @7 Z: \# ^1 ?/* fb_check_var函数用来检查可变参数,并调整修改可变参数 */! `" I) z! S1 ?# v
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
4 m6 a1 I7 Q3 }7 j E4 R; }/ D。。。。。。
+ ^3 G% b8 w8 Q) r/ g6 l/ H6 U9 t/*fb_setcolreg函数就是用来设置fb_info里面的pseudo_palette调色板成员 */
6 {7 q# R2 s, v+ g3 F+ M2 B2 p) a3 rint (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
3 z) J; S% i7 n' B$ Y unsigned blue, unsigned transp, struct fb_info *info);: Q8 H' P- |0 p- B' F! t2 x
。。。。。。
% E6 F6 J6 D! {/ x- }( Q) c9 p
- K0 C+ i) d; ?/* 下面三个是通用的函数 */
5 v- q( N! B3 r' ]/* Draws a rectangle */6 i/ F1 N- O' g
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
) m" ~3 y. w: x) c/ N/* Copy data from area to another */
M+ `" R/ N4 \, j' r6 T9 Wvoid (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
" `. W5 c+ I) J$ v/* Draws a image to the display */! k8 G* @4 w( A4 w0 n% O, G0 x
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);+ s1 h. C% `2 y6 }" E
。。。。。。
6 l& b9 C8 [( g' c( P; w/* 有了fb_ioctl应用层可以通过ioctl系统调用来设置屏幕参数等 */; _9 h- g2 t3 M) t
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
) l1 V$ J5 K% l _6 m- Dunsigned long arg);
" Y+ r7 z- t% x/ F" f。。。。。。; T! V/ S1 C0 x5 O" N
/* 有了fb_mmap应用层可以通过mmap系统调用来读写帧缓冲区内存 */
+ I4 P; c) {( a( X) Uint (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
. @8 P5 E3 N1 G8 f( n。。。, \+ D3 l0 ^! R' L( d, C8 g5 B
};/ R9 j, J4 F- f- x Z5 J0 y0 A
; F5 H0 c" S, F/ P- Z! x, L' ]4 A3.fb_var_screeninfo 结构体(在include/linux/fb.h文件里定义)
; m3 B0 G; f2 C: u1 U5 q% u; b# \$ J, h( W! M
fb_var_screeninfo 被fb_info结构体所包含,这个结构体主要用来设置LCD屏幕的参数,如分辨率、像素比特数等,LCD驱动程序里面硬件相关的设置很多都涉及这个结构体。+ t" J$ a. V6 [0 F
+ |. ?* x* G, [& ustruct fb_var_screeninfo {
6 Q2 v* ]2 {# y2 b9 n__u32 xres;/* visible resolution,分辨率,即一行有多少个点 */
7 W. M ^4 L7 T; B: V" w__u32 yres;. O4 l7 O4 q5 D6 z% m' M
__u32 xres_virtual;/* virtual resolution*/% q2 A _4 y7 }: f S
__u32 yres_virtual;" ~, `4 ]4 k/ J4 B* s, R/ T. y( G7 b
__u32 xoffset;/* offset from virtual to visible */
* Q" `! W' |6 C# |3 |__u32 yoffset;/* resolution*/# K* h4 R7 N4 _3 X4 G' V0 r
+ Q& X% ~1 U' g/ F/ {1 Z; u. p
+ o: w9 `0 D/ `+ K; ]__u32 bits_per_pixel;/* guess what,定义每个点用多少个自己表示 */
' {- M4 @( V3 V7 Y+ K__u32 grayscale;/* != 0 Graylevels instead of colors */% \5 B+ P9 O; e" e/ R
2 M; N# l% k; Q
8 G1 C" [, @4 M7 S8 _. i4 w. ]$ pstruct fb_bitfield red; /* bitfield in fb mem if true color, */
! Z/ q) `3 w; M% b3 F. ?struct fb_bitfield green; /* else only length is significant */
1 b. C6 h3 |% ], M' Ostruct fb_bitfield blue;. z1 l& }; o8 b
struct fb_bitfield transp; /* transparency*/# v" @& d8 X1 h9 e) O6 J8 ?; k8 J
2 t7 g4 K$ M' b. o6 E# @: H
/ c2 ~% C/ L. h( W& y% I3 H__u32 nonstd; /* != 0 Non standard pixel format */
) I% E0 {6 f$ O! H
0 p9 ~1 Q2 l* {5 g$ I% L. S; r% [$ [: ~8 \
__u32 activate;/* see FB_ACTIVATE_**/" ^' h; | @- \: e! D+ l8 c
8 z) p. H; x/ L
3 ^/ w6 Z l3 e W4 I! W/ j4 U__u32 height;/* height of picture in mm */
- ]+ J+ o7 }) d, B) J__u32 width;/* width of picture in mm */- m7 F8 Y* u. q, ]
- o( I6 }) O) X- ]+ f+ _! s) y% a# K9 Q1 ]+ z
__u32 accel_flags;/* (OBSOLETE) see fb_info.flags */
* V* \, |6 f& G) u+ ~5 `7 s: {% E4 i9 {) `1 H" B& a
5 H) r" V3 z2 [) X- u" a; e/* Timing: All values in pixclocks, except pixclock (of course) */% d$ ]% L0 ?- y0 i9 u1 s& j* U0 s
__u32 pixclock;/* pixel clock in ps (pico seconds) */
; S! K, e5 U* B3 Q__u32 left_margin;/* time from sync to picture*/0 {' I+ ]! p$ u1 @ d- e
__u32 right_margin;/* time from picture to sync*/( P" ]5 n7 u V: O
__u32 upper_margin;/* time from sync to picture*/
4 l, \2 g$ P2 B1 j* _* P: d5 a__u32 lower_margin;9 y" B8 B1 Y, N8 g! M
__u32 hsync_len;/* length of horizontal sync*/
( D* z: K) `- A; D* g" p/ X) P! r__u32 vsync_len;/* length of vertical sync*/) d# C0 Y5 o2 K
__u32 sync; /* see FB_SYNC_* */6 u( I& n" j, ?/ _+ v& c
__u32 vmode; /* see FB_VMODE_* */& N! {) D6 ~9 Y) v4 B
__u32 rotate; /* angle we rotate counter clockwise */# H2 {& m- z+ w5 V
__u32 reserved[5];/* Reserved for future compatibility */2 _" t' U/ Y# _1 W
};9 \2 r* Y% {$ F% v# i
1 d+ E& A7 f- q/ Y4.fb_fix_screeninfo 结构体(在include/linux/fb.h文件里定义)
3 m! o; N' _" F, k8 Z3 ?
2 Q0 d4 s8 M4 Tstruct fb_fix_screeninfo {
4 Q0 p4 d- L7 P4 _0 n' ochar id[16];/* 驱动名字就保存在这里*/* N/ C6 ]6 f9 r+ p2 j
unsigned long smem_start; /* fb缓冲区的基地址,这是一个物理地址 */# x5 `4 R1 u* E$ o. J# H' t
__u32 smem_len; /* fb缓冲区的长度 */5 T) T1 n2 H; B! C3 w1 i
__u32 type; /* FB_TYPE_类型*/( c, n' \# }$ _. @# F* t$ ^% W( s
__u32 type_aux;/* Interleave for interleaved Planes */
1 B, h+ r6 |+ Y9 V; @- Y__u32 visual;/* FB_VISUAL_类型*/
0 p+ Q4 W0 L6 D; E7 [% M__u16 xpanstep;/* 一般设置为0 */
* X4 Y& }$ w7 I1 ]7 s+ ?; O__u16 ypanstep;/* 一般设置为0 */2 w4 L# Q+ }2 v- ~# I% B3 v
__u16 ywrapstep;/* 一般设置为0 */9 k. k) R# X1 `0 }2 a* r! r4 h
__u32 line_length;/* 屏幕一行有多个字节 */
" p" Y0 Q4 L @$ g3 Qunsigned long mmio_start;/* Start of Memory Mapped I/O */
+ C0 m; w, C% |1 q% Q/* (physical address) */; R6 Q8 E$ q! a
__u32 mmio_len;/* Length of Memory Mapped I/O */
+ o# \9 F8 \; n0 ?__u32 accel; /* Indicate to driver which */" n3 m" L4 t" R6 N+ D' v1 E
/* specific chip/card we have*/
' ~) y" s% ~' Q* E% W* x. A__u16 reserved[3];/* Reserved for future compatibility */
^+ N S* D% G' K' D};' ]! l" g' c' q3 B# ]# {+ k
' Q9 _: F9 Y0 U0 \* {' ?6 `0 d0 @以上笼统的介绍了几个重要的结构体,大家如果没有阅读过源码的可能对这些结构体比较陌生,但是没关系,比较常用的我都用显眼的颜色标记了,大家结合以后的博客日志就会懂这些结构有什么作用了。
4 T/ [4 x( O4 p" j& e! ~- d
; ?5 G( L1 B B1 v2 D& A( d3 R5 Z对于这些参数会在哪里设置?通过什么样的形式来设置?
+ U* j2 w. b8 {" h; ?9 G9 K6 Z0 N9 B/ V- q9 N# Q/ L
答:通过平台设备的方式来设置,这就是鼎鼎有名的platform_device结构体了,这个知识留到后面的LCD驱动篇来讲解。! K( |4 _5 P: p1 H
9 M+ R9 a6 q- Z( b+ D7 C8 N s7 M! o( H5 l% \! S1 y
: Y& i9 B: z8 o' { |
|