找回密码
 注册
关于网站域名变更的通知
查看: 265|回复: 2
打印 上一主题 下一主题

linux字符驱动之初见

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-4-27 10:23 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。( H7 H# B# r5 G& g: {5 l
; j0 h8 j+ q: \7 }$ n5 u1 o
这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。8 A; g$ O* v+ L
0 V: q) A! H2 ~- ]) ^, a. v
一、字符驱动框架2 R$ e7 e. O% f- y& K' J
; ^2 K) m, g1 T
------------------------------------------------------------------------
: h# e  O; m1 C0 E$ O  ?4 g$ l% B! A2 s0 D- }# _
APP:     open               read                   write: _5 w( d: Z5 t8 F& T7 W
" c1 b8 \0 M6 X" R8 p9 G
------------------------------------------------------------------------
4 N1 d* E- `; {+ J9 |
1 I6 b; _: S: l. n- JC 库
" M- x2 P" R% V4 D# h6 Y  S0 ~! e& D0 B! n2 n6 V( ^: y
------------------------------------------------------------------------7 o2 P# N# |- s

- I, v  e( D0 K3 x9 y      system_open    system_read       system_write: w2 F) F& ]% ^3 `0 _; F5 ^% B
1 e& Z5 F* V7 B9 \: C) ~

7 V6 ]; \8 g3 _: X! h8 u1 l
* W8 X- w' N/ ?8 J- f5 ?' W# m------------------------------------------------------------------------
; v) _$ S) L! ?# s; V& w* S  K' x9 t) T5 d0 A
KERNEL:8 v( }5 h' @  k/ f8 _5 o4 e
; J$ F* H! m( j. T- C/ p, t
      led_open           led_read               led_wirte
- [6 ^. j  ~# w+ j7 g4 |
" ?& M7 ~, m+ Y  f& F8 s------------------------------------------------------------------------# o2 |+ C2 W* c6 Q. |2 J9 ~6 R

4 H0 I9 @4 ^& h1 l9 u7 F  ~! c5 N
# x3 P% ^2 Q* y: l% m( U" S  M! d' `7 C& A0 {8 M: _0 @  x
问:应用程序open如何找到驱动程序的open函数/ C& t4 z) y4 m1 w

3 b( {3 w6 e$ N答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
. R/ h+ X/ M8 W1 }/ i# h2 X' _1 s; T' @
问:通过什么样的方法来找到驱动程序的open函数% y, _1 c: Z7 l+ U$ `
( }* ]$ w' T1 m+ P' K/ \% W  d8 X' E$ _
答:通过一个注册函数+设备节点
$ u8 y, p; f1 e8 _( m' H+ ?. E2 a, y, R1 V2 {
注册函数如下(旧的注册函数,新的以后再说):
5 x" i2 q! i. ~5 [" Q# w& [' u& H, q2 j/ s0 ^+ o/ V
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)% G$ O7 J: n! i; Z3 T# S
/ C8 B+ P& |, w
参数1:主设备号(重要)3 I4 V9 H& q( N* v9 `
$ |' P9 a  a. M& P- G& `
参数2:名字(不重要)# f: U: {9 K* y+ M3 ~) h7 o( S

  T+ Q/ v  i" ?( R2 h& ]/ O5 K7 {参数3:file_operations结构体(重要)) I9 ^. e6 [* |4 O7 \

) h7 s  [2 O( C; l6 I设备节点:2 {7 t6 f* A, q* D& e) g6 r( q

; X* d) Q' i" V# i可以手工创建也可以自动创建,这里暂且只说手工创建
( z/ \/ x6 }8 ^( {9 Y2 G8 g0 t+ _( T& h" J4 v1 E4 U+ \9 @8 E
mknod  /dev/xxx  c  252  0' t; Z' B0 Y0 h

; o4 y% p' J7 k8 A  s具体什么含义,我就不多说了,看视频吧,很简单。0 m$ ~, o1 n. }  A1 L

: f) c3 Y( a1 ~$ }+ H4 q: T2 D( R
7 u7 c  m+ @, v" {) _
  @: F+ F0 y; S9 }3 J问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?5 W) r4 K- R9 g  K7 S, h6 x) G
: I4 A% }% I6 @- h, S$ k
答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
, R# g! x( W" u: ^8 f  P# f4 X* c- o8 y: x" O; u/ C3 E
例如:module_init(first_drv_init);  //用于修饰入口函数
( h* Y. D$ G! C% N1 z' \$ s( `
2 O" i; E" M( c自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。' C2 \# `" p2 z

+ l8 N( S, H/ k8 P8 n) W例如:module_exit(first_drv_exit);  //用于修饰出口函数
, k8 q' L3 Z4 K- \1 I- u& a, V1 R1 h3 C5 n

+ o6 v7 M8 ~/ k$ w) E" C
& }7 L) e" g( {7 ^$ Y( g+ W驱动源程序如下:
; b. J  I" S$ d
5 g/ f! S. K, K% a& X9 B! r
( T" U! `9 y, U; {, d9 B#include <linux/kernel.h>
/ M  q. Z' V/ f8 N; y: p% l4 z, k! I#include <linux/fs.h>' o) f, n$ S" _7 {& n- r' O, I
#include <linux/init.h>+ M0 {2 W+ t7 v+ x
#include <linux/delay.h>4 ?0 v; w7 r8 T, N
#include <asm/uaccess.h>( d+ O3 R- G* l- L( _
#include <asm/irq.h>. H0 h# }# W. v6 s/ w
#include <asm/io.h>- g+ Q) r1 s4 E3 W
#include <linux/module.h>
/ F; [! t2 Y: w' K
3 G( Z( i5 m7 J2 f
  o. W$ g8 R5 [/ k4 |% `int major;
" s4 w1 ^7 a0 Q6 k0 j% l/ Hstatic int first_drv_open(struct inode * inode, struct file * filp)
5 Q$ Z, V+ g3 \. A{6 Y( z& P+ I3 @: q4 K
        printk("first_drv_open\n");  `$ Y: i! A7 z; E0 N
        return 0;2 L% t4 A, q! I- [4 j
}
8 c" `( D- T! J) D. t. istatic int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
+ ]! |) ?5 e1 {# }' x{) p5 v( i  {( M! [& O
        printk("first_drv_write\n");
3 S& H. r6 h& C        return 0;
8 s: |1 l* ~8 V9 ^  d) d}
. ?7 Q/ N4 g5 e) P, W9 s1 ]3 T
& d( \: v3 i0 l, T* w5 b7 p/* File operations struct for character device *// A, ?2 [% ~  V+ m/ a! \8 N- k
static const struct file_operations first_drv_fops = {/ U  z. p5 K8 b: I$ S& P
        .owner                = THIS_MODULE,
! t  f3 {( K1 M        .open                = first_drv_open,
: b4 Q, G/ O( D! g4 v2 q        .write      = first_drv_write,6 r# E6 W: Z% A
};/ l& U: s4 q) r2 M/ @, X& P

' s6 g8 r! j( O4 k; |8 Z/* 驱动入口函数 */
) `# p! Y. o2 {, o, Mstatic int first_drv_init(void); _, _3 f* v: m! ^
{
0 o1 p5 p: p" {: d( b  W        /* 主设备号设置为0表示由系统自动分配主设备号 */  e. P% K4 f# g4 z! A4 Z; P1 H) \! `
        major = register_chrdev(0, "first_drv", &first_drv_fops);' R6 D" `* N! H( v9 l
        return 0;2 I1 X* I3 n) ]) b
}
; X6 _% V5 v( F: e# J2 S0 ?5 l3 w
/* 驱动出口函数 */
3 @" A) ^& b: u- e! Gstatic void first_drv_exit(void)0 |( B1 Z, l' Y0 ^4 G/ i) ?
{, R! ^6 O+ P( k! M$ A- ]8 o+ R
        unregister_chrdev(major, "first_drv");9 n9 C  [# {' M
}
% R9 F3 V- b! R' u8 q: Q
6 C. |5 {$ e% t% |& r. G3 ymodule_init(first_drv_init);  //用于修饰入口函数
, i. R$ v9 Z' Q- A; Omodule_exit(first_drv_exit);  //用于修饰出口函数        " ]. D+ D! s# F, u  e4 R" J: H
6 F, I2 u3 o6 @: w' A; c& Q
MODULE_AUTHOR("LWJ");. E/ L) T+ C$ E) B
MODULE_DESCRIPTION("Just for Demon");! D3 }3 b3 i; `( M/ E
MODULE_LICENSE("GPL");  //遵循GPL协议! j$ }( o- a" o  Z
7 H$ S: O: f8 r5 D4 l, y4 l& M
Makefile源码如下:
9 o4 k* t; F5 d. ?7 y" T5 p% {6 w  w
8 y7 p' h1 D/ E( y/ bifneq ($(KERNELRELEASE),)
6 H9 e# a' s4 B; \* d9 ~4 p3 L% e; [2 ^- O. t/ K$ \. S/ Y
obj-m := first_drv.o
" j( H) o) T8 n, D* V; B, U. w( e( I, e; A  O
else
0 M9 X5 \/ [8 Y; v( h: Y       
$ d8 r  B* Z1 l/ |- m1 H$ l+ R/ nKDIR := /home/opt/EmbedSky/linux-2.6.30.4
" B; a6 {' g% H; W  I' p& r; X* g
all:
$ K* A; I8 }0 b, ~+ |        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-6 E8 W7 g" k0 G3 ?
clean:
+ Q$ R: n) G: M- e        rm -f *.ko *.o *.mod.o *.mod.c *.symvers/ C# u7 X/ z" T, Z2 E* E
) G  ?7 L: {- \$ Y+ y; t' b! {
endif( F; E3 X3 J* I& o2 o

4 g" h/ N) t* l; H测试程序如下:
$ S2 \2 u: @" `, j( h! h7 E9 Y+ v9 Y6 e+ _9 }/ L1 O" h5 I
#include <stdio.h># o5 \: Z" I' }* s& q7 F) e
#include <sys/types.h>  o/ e0 C. r6 w6 n9 A
#include <sys/stat.h>
. @3 D+ y& g7 k#include <fcntl.h>% W3 _- p  k& o
#include <unistd.h>
1 n- B: v- |$ B7 \; V
* q9 X: v0 `$ j" _6 o: fint main(void)
0 \6 m5 {0 k* O* a; y9 @9 y) U2 I$ Q$ o0 n, K+ O8 M
{5 r4 U3 T# v- `. r
        int fd;
% b) T; Y" ]+ X; ^5 |4 F/ N( G        int val = 1;) {9 m3 b; W4 w, Q4 G: _+ e' X6 y6 _
        fd = open("/dev/xxx",O_RDWR);1 b" p; r: O1 I9 j
        if(fd < 0)1 C7 p) ]2 k+ `! @9 Y9 h1 e6 k
        {* P) l) d' G) s, \1 r6 Z# i+ m
                printf("open error\n");
$ Q, J! x) [/ w' e        }
0 c- g; z9 ]- z- V5 P  ~       
# ^" z4 n( ~* j" P% g        write(fd,&val,4);
' o% k( z' g& {) u" z: I: s$ U       
3 J6 [9 P% {2 T+ g        return 0;* c( o( C- s( u
}3 i% |, J1 V- E/ F

2 I& r$ d; [) z9 P, U开发板上的测试步骤如下:
7 G: B, q; Z; z3 Z0 u: H
7 e! Q4 y1 A$ O[WJ2440]# insmod first_drv.ko
1 h. m2 t& J, [6 J6 P! J1 H[WJ2440]# ./first_test ! ~, q' M) I, B3 ]* z% c' v
open error
: S; t! X, ^! M[WJ2440]# cat proc/devices 1 Y& g! Y6 [# v1 Q
Character devices:
# R: J+ @' O# s! W  1 mem: O8 V2 O: f. k
  4 /dev/vc/0
  A/ M( a# a! i5 E- f4 k$ u  4 tty  p9 @  ?; C" q; ^& Q; q& |, P$ I
  5 /dev/tty+ E4 W( {( d1 ~& }: o
  5 /dev/console
7 H" J; M8 i" s  5 /dev/ptmx
  h# y9 y; [4 p8 ?  7 vcs
9 E( s# }9 V+ ] 10 misc
& R) P4 x' R+ h5 v 13 input9 O6 b; R8 M! f7 }
14 sound$ v* I. j( z8 n- p
29 fb
7 L- [+ D+ Q  J+ S9 x 81 video4linux
+ E2 B. ~& P; w, q8 r" E: C 89 i2c/ D- X, J% c# c
90 mtd% i  s0 Y1 ~0 l$ K% S
116 alsa
, w* t' b6 }" s% ~$ j" u0 D128 ptm: N7 {/ z  v& Z; }1 ~7 U# _
136 pts  M4 o3 l* e4 X% P
180 usb
8 r% P- A: Q: P188 ttyUSB6 r% W. h; M& b; x
189 usb_device
( h& v8 Q  d( c+ `204 tq2440_serial
* f/ N( ~% Q( h252 first_drv7 a3 a9 k# ]% j: v2 {! o& |& D
253 usb_endpoint% K6 W4 p5 \$ O$ j% v3 |
254 rtc7 G* X, G1 Y4 B9 L  R9 o

4 F" @' P1 j! qBlock devices:0 ?; }/ f! w2 F
259 blkext$ Q, N/ B. L" W& E0 S+ M
  7 loop
! M/ _2 n8 H  v7 j5 s9 R7 g  8 sd
3 A" L% K0 {9 n* z6 G7 B# w$ }* M 31 mtdblock# V9 H. w5 p# f* C0 t/ a
65 sd2 N* c" e, j) [% A$ O+ t/ s
66 sd# J0 @, V7 O" R5 s! U  g
67 sd
/ \( \: O1 j! Q/ P; Y 68 sd
: b# `' F/ l9 Y 69 sd
+ F5 Q! }7 e" [7 H4 Z1 o. Q% f 70 sd  _) A. k5 {2 m3 V. K
71 sd! l) D! Y, s& ?- ]
128 sd
% c7 ~$ ]+ G0 o7 T0 U2 Q* S129 sd% I' P& V' O& W2 M
130 sd7 ?+ W; H6 [7 M0 X  ]
131 sd
% {( o+ ~& }* C" o# `) i: ]132 sd
# r; ?* R/ d+ M: B133 sd
' O& ?' u' h5 @- x- i( ]134 sd$ w- w0 V4 m0 f9 i, ?: r
135 sd
. F) C! Z4 k- {' e179 mmc
; [9 \7 w: `- @6 s8 ]! K+ e) O  V[WJ2440]# mknod /dev/xxx c 252 0
4 _) Z: K) Z; Q1 K  z[WJ2440]# ls -l /dev/xxx ( F  u+ h& \- d* z% U; b* R1 R* }6 v
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
7 p- _) p9 R4 r) p8 x# w9 y! {/ _[WJ2440]# ./first_test # V/ j) D$ d6 t9 j  W1 {8 X8 k
first_drv_open
4 Y) g" e& W9 G- M" G6 E/ K! pfirst_drv_write& ^6 p& ^5 N0 D/ z  ~
[WJ2440]#
. P, m/ q0 ]. e, u, {3 R# a' u
5 i; U% Q& u" E9 E0 o
& _9 s, Z1 I# b  h* j. L
' C, y" J9 A) s! C, m; Y
  • TA的每日心情

    2019-11-29 15:37
  • 签到天数: 1 天

    [LV.1]初来乍到

    3#
    发表于 2020-4-28 13:56 | 只看该作者
    linux字符驱动之初见

    该用户从未签到

    2#
    发表于 2020-4-27 13:22 | 只看该作者
    linux字符驱动之初见
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-26 04:40 , Processed in 0.156250 second(s), 25 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

    快速回复 返回顶部 返回列表