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

初见linux字符驱动

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。
" o& }+ n" }( A. e9 w) ]' ]$ `) C) f2 a; `( |# n# j/ Q
这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。
: G- |: x0 W5 [, e; N3 W$ D. N
' F. T* u6 C( w) n# K0 m& p一、字符驱动框架4 T/ X( Z) m! D3 z( ]# M+ i

( p. T8 [/ u- P5 y: b------------------------------------------------------------------------* p* `) u5 u0 M. }' n

) M" L3 k+ ?, VAPP:     open               read                   write
. T2 r8 ^- c# B8 z! C* P
9 @) b% ?- L% j9 t# i( Z$ c------------------------------------------------------------------------9 L. O# }1 \7 n  w4 b

  K) F% M- d3 C7 `/ aC 库9 \3 x1 _& _4 @& s4 |

8 v* j: F4 A. ~) w/ G2 a------------------------------------------------------------------------
2 x4 C- _  O' Y; p8 a
  @, R& G* i$ u8 X9 }      system_open    system_read       system_write
5 c$ Z; u2 N' D7 z" N; V# ]# \$ @7 v+ {, D

% f  w+ |1 m& h2 H  Z( Z' R( w) K8 Q4 ~  n( b, N; H; F
------------------------------------------------------------------------/ n8 H7 A- V4 m  h& U

% |7 j5 f' D8 K( W8 {( Q! f& `1 H4 BKERNEL:: f2 M) R) b+ p+ i2 T  n
4 _* ?; x2 r8 _* M
      led_open           led_read               led_wirte5 q$ g9 w. w+ P. A+ s) d

8 ^, x2 }1 ~6 ]" ?" H+ V- ]------------------------------------------------------------------------1 U- U( x& G5 z, J! R. ?7 t
) `0 r. c% p  ^

# F7 n: D* U. f0 |. B) v5 C( {, z2 L* I
5 v* _% S. W7 H2 W1 e+ G  c- D/ G问:应用程序open如何找到驱动程序的open函数1 o- A# U! u3 [% c4 v9 d* {

+ w& F- o. q% f, C- U$ ]$ G* G2 I答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
6 d7 p: r% r# J2 c* b; S: v5 V9 M5 C7 z9 V1 X% g! k$ i/ b) m. Q
问:通过什么样的方法来找到驱动程序的open函数
& e* E' n; i. `9 K0 m0 o" J
8 _8 x$ x+ Y0 O# v4 t0 Q: b答:通过一个注册函数+设备节点( @+ B; Q' f& S+ Z0 A; M: z8 |% @
, s, g5 [3 b6 D0 M, q, u
注册函数如下(旧的注册函数,新的以后再说):3 l2 y4 z$ {6 o6 I  N( `
5 y4 c4 Q# z) @* z) R
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)/ E& w% Y4 I* @# l
( @2 V" v% i  V. i- I- p' M
参数1:主设备号(重要). z8 s+ }5 i, d

2 r6 s5 i3 Q3 {  _3 a参数2:名字(不重要)% v5 y2 {$ f: O; F* P

1 S. _# ?, _" Q0 y参数3:file_operations结构体(重要)
/ B2 J& \. g, O9 d
) q' u* P6 S3 b. n3 a设备节点:
! c6 i2 c; ^& C1 I6 A/ C% L
$ k, i: {% U! @可以手工创建也可以自动创建,这里暂且只说手工创建- G0 W$ [/ h. ?- k

1 s' b9 [# L" y6 h0 `4 ~mknod  /dev/xxx  c  252  06 s& e" m8 ]. y$ u
9 }* Q% ^8 o; ?1 t
具体什么含义,我就不多说了,看视频吧,很简单。
' k3 p, O5 V6 s2 W6 @7 q/ y( @- }
" H2 g  Q5 J- Y# h- M
* T& ?. k  P9 l. E% K9 h1 s" \; I4 \+ w# p
问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?
  ^" \- o4 H% v- v* w
5 }" k- K1 I' g3 S3 y* a答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
. b7 @* A* ~: a% a7 |% V3 i
, v& ]1 s5 O, t* Q& v例如:module_init(first_drv_init);  //用于修饰入口函数
0 h5 a- S8 Y& m+ z! u8 E+ h  m. j0 c, s
自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。
% o, I2 H8 h2 i& v& m8 k2 p  Z8 f+ h5 U, k
例如:module_exit(first_drv_exit);  //用于修饰出口函数9 F# K% Q+ _' Z8 N
! U+ u' `; o8 |" |' K4 f4 |

6 b- b9 ~- Q* t9 J4 a+ g$ L9 ^* n& y# Z$ `7 c5 I. p
驱动源程序如下:
2 f4 P: ]# v' R2 W: Z1 t* w1 W- E4 f4 B

$ A$ m% a1 v, q# {% `% R#include <linux/kernel.h>
6 k% }) Z" |. o#include <linux/fs.h>
* u7 F7 ?7 @9 p$ j6 S#include <linux/init.h>
; K6 F  {$ O/ u( f4 U+ s6 J* X9 i- N#include <linux/delay.h>* ?! y% @( ^* R% J
#include <asm/uaccess.h>* d( P. c" T' W9 v: @3 f& R
#include <asm/irq.h>
6 y4 d2 J+ ~8 f! n- u#include <asm/io.h>  }& G3 _1 i. n
#include <linux/module.h>
" B; S* Z* A& Q/ b9 J3 Z9 r3 d( y& V2 o

" r# n0 f" ]" |int major;
1 j0 B$ b7 u# b- [, Rstatic int first_drv_open(struct inode * inode, struct file * filp)7 G6 V8 u: A4 {) G( \( |' K' l9 v
{
4 N# j4 T0 ^, n* H3 m8 k9 s        printk("first_drv_open\n");
* i6 Q1 k5 z, K1 G/ }        return 0;
( O9 j) \3 L/ E3 z! g: Z$ B7 J9 J7 p}2 p4 o' n" H$ Z' n: A; c9 g
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
2 t% B+ o( L; X, \2 g* k3 Z{
1 n: Z9 I% J# t- S        printk("first_drv_write\n");
: a4 h2 N! h+ c9 f$ c        return 0;  r/ S6 w& t* w% {& V
}% g& E$ R6 P; d1 D5 R. I
! C& R# `0 o2 S9 g* O
/* File operations struct for character device */
3 x# U  B( B, z& Ystatic const struct file_operations first_drv_fops = {
6 B# _  L" ]0 {/ m) E' c, k        .owner                = THIS_MODULE,+ N- w: ~8 H& r
        .open                = first_drv_open,6 W1 t8 u( n+ s+ P. E/ o- o
        .write      = first_drv_write,
) T5 l" f  ]/ D/ l( P+ [+ ?};3 D% y( J% L( d, P. q

5 N; D4 S. k8 \3 C' Q* \/* 驱动入口函数 */: P% W, M% l3 m7 W
static int first_drv_init(void), y" X% x. ~) A4 y) V, n8 [7 l
{" E* L9 F' g+ B5 z( J3 D$ S
        /* 主设备号设置为0表示由系统自动分配主设备号 */4 e% u6 D7 E; D. z1 ^! U
        major = register_chrdev(0, "first_drv", &first_drv_fops);
* K1 q9 x/ v( Y' @2 ^6 q        return 0;
8 w% P, }' B- _8 ?+ [) Q$ u}- @* N8 r9 r6 _$ `! a3 @
* s+ R! _% p/ {; W- g) d! j
/* 驱动出口函数 */
3 n! Z# G, g, h3 z/ A0 _static void first_drv_exit(void)
2 ?8 ]' n* j$ G3 I" @6 A{
3 N5 q& E9 z. `( i3 k4 Z( S0 Q5 J        unregister_chrdev(major, "first_drv");( z/ c  P( {- O2 k, Y
}4 D" j( w& M5 p6 c/ i8 Y# D
; ^0 F% q2 ~" o% ~% @! F
module_init(first_drv_init);  //用于修饰入口函数
. R, h/ b% e: f6 U0 k- l" Bmodule_exit(first_drv_exit);  //用于修饰出口函数        $ h8 G  I8 `) A& Z1 [4 L

5 n3 N0 T2 I! A' b9 yMODULE_AUTHOR("LWJ");6 N$ y/ Z- m; E8 O9 V' S
MODULE_DESCRIPTION("Just for Demon");% x% [& L: M* |1 \
MODULE_LICENSE("GPL");  //遵循GPL协议2 ~8 _+ a2 u' A

: j# g+ H" A. \& k) h. z( Z% w$ hMakefile源码如下:; Z4 F* `, L- n8 ]* s( `2 N' x9 g

' x( P+ u3 @, p5 ~1 Y& Z7 ?ifneq ($(KERNELRELEASE),)
; @% [( E$ P$ f0 h6 g" d. y* c- n
obj-m := first_drv.o$ T# `: H/ [! C0 L4 ?0 ?
' l& @: U+ Q1 B& ^$ X+ \
else2 t3 H5 o' q+ `: m6 k. Y7 ~1 [1 }1 W
        0 \. l/ `# r% f/ }& i! J
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
  D7 w. Z8 [; ?, D  y/ A2 w
) s  {: u  h. v0 ]* {all:
0 Q4 `" U, U& }        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
$ P. Z; K3 [$ v' J6 `clean:
6 J8 E0 b; c' W0 |5 A1 @' Q        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
7 Y( {$ M" ?5 ~2 Q( i( ~
; l% J  H0 e7 f  k! R- O9 V6 tendif
6 ^6 P2 e+ A- D# f$ v2 H
( r$ U8 ?* Q" _) E- C2 Z: n8 F+ H测试程序如下:2 y, J; ?5 N2 H3 K2 ]& t: U
$ w% ~+ E0 j- }& m1 G+ w# q5 s' A
#include <stdio.h>
7 I  |0 l$ m: m7 H& V#include <sys/types.h>
7 v! V' u  e/ u  R2 L#include <sys/stat.h>7 D9 _2 `: `& I! \! W. {& ^. Q  K( e
#include <fcntl.h>
- Q' X5 `# p. r: q% G#include <unistd.h>% S0 q" a& ^/ @

7 N) q- T' ~7 E3 cint main(void)
, ?- y- d5 O/ _6 C2 K0 W4 H
0 h! b$ L) S" }2 Y- L7 s$ v) T( T4 q{+ s# L: {: k6 ^. t$ p. [8 Z! u
        int fd;
% R6 I& z; ?! a2 h2 w7 G        int val = 1;2 k/ e2 D) [' f/ \+ U1 d
        fd = open("/dev/xxx",O_RDWR);- P, e0 h4 W. ~' [& b3 `
        if(fd < 0); b6 @7 }5 S5 Y/ M% H+ e! U
        {" |5 A+ Q) w& }: D
                printf("open error\n");: b3 k' t5 r* T; _' ]6 ^+ m
        }5 _2 |  D3 X! Q
       
8 _1 H8 Q* z: d% P        write(fd,&val,4);
8 d2 a: j4 M- V1 @4 o0 ?       
' w5 G5 j0 g( h0 `8 M( l! R        return 0;3 C# {, I1 ?6 C& t' P# n
}0 N% {) V5 }( k0 T8 A/ k" F) U  u

4 k( v$ L, j' b! z" ~开发板上的测试步骤如下:* m( O1 ?  Q, Q( H

8 c- L! K/ `9 @+ M- c7 n[WJ2440]# insmod first_drv.ko * R/ w  O8 v( d1 Y( I  g
[WJ2440]# ./first_test
( {9 c4 q$ _4 N# \% x* o/ Fopen error
( s- j6 ]1 q6 ^/ {[WJ2440]# cat proc/devices
1 }9 h; H* Y8 @2 k* h) G" [Character devices:
9 T3 n+ X1 J* e0 E0 Y  1 mem
) r) S) Q9 b$ ]# v% B1 Q  4 /dev/vc/0
- J) e; E* g4 l; w  [" D  4 tty( M9 E; I  P( R$ _' T9 G
  5 /dev/tty1 l. ]" E! |9 f# u5 I
  5 /dev/console1 S) Z& M- S3 @
  5 /dev/ptmx& A3 J0 J7 F. k# S% d2 ^4 ~1 w
  7 vcs$ l( k2 y. l0 b3 x  {
10 misc6 [- h' [0 u, T" d$ F
13 input
5 t5 U: X- d: ?9 g0 N' X; \) ] 14 sound
$ n; N8 l7 N( I( h 29 fb
/ B" ]4 Z0 U1 }- Q* _1 v 81 video4linux
/ r% J% g6 G1 m' B0 p$ { 89 i2c, i" S! C) C+ N( l
90 mtd
( S* n6 Q7 [0 K8 P& G* p116 alsa
' ]1 q0 T) L& p# e128 ptm& ?7 \4 B- ]) R$ U
136 pts& `4 f1 s( d# v' [! X$ A
180 usb
* ?2 p- ^& i5 C3 L& P6 m9 k) b8 h188 ttyUSB0 G& R1 B, k$ y0 ~1 Z
189 usb_device$ k4 b* Y% l0 \% A
204 tq2440_serial
) a) W8 S: I+ s252 first_drv+ ^5 o% S" ^8 y5 a( [' D
253 usb_endpoint! }3 T: y; [4 v+ o6 Q. X
254 rtc$ Q, o/ R, h+ V* }: f

4 q/ E- v0 o6 {/ s$ `! oBlock devices:. H7 X/ B% M0 }9 k% e3 I
259 blkext0 V/ Y+ L4 C% w2 Y* N. ?
  7 loop3 u( q# P* D( P2 Y& G; x- G) P" [
  8 sd
6 f- G- T' s" ^9 G! X 31 mtdblock" p; c5 |3 R. C) S+ v$ r
65 sd
' [5 R# e+ q5 E+ i4 n7 n( z 66 sd- @0 G; r4 d  w$ w; \; k4 V9 r! p
67 sd/ u- _6 j" n% ?
68 sd
2 X6 i8 g7 p2 x$ [' j 69 sd2 x" S- d  d8 a2 v, y5 o$ h
70 sd% a' |' g6 U7 Z6 z+ V8 i' [0 w. o! n
71 sd4 @' h+ T- s. e% c* |
128 sd
. ^8 l2 T: V9 [129 sd
0 c1 L" S- x/ N, M130 sd, x4 }0 A9 v) f1 q% E2 @4 v
131 sd
' j. B* U. [0 P2 l. S1 d132 sd2 ]/ P& r$ i& \
133 sd; P3 g& \1 {6 g5 H' C
134 sd
* x$ H/ x) x0 M' B, b! T135 sd3 F1 P" g- P6 l* ~
179 mmc/ }' `# a0 D. G3 B
[WJ2440]# mknod /dev/xxx c 252 0
9 }$ X; w: A1 A) Z[WJ2440]# ls -l /dev/xxx 2 X5 Z! R3 b" ?- w  v( K
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
- w. ?9 Q  a, w[WJ2440]# ./first_test / S/ O9 l# g6 U  g
first_drv_open
+ @& S  D" |% g2 q8 ?5 s4 Y7 D6 efirst_drv_write1 X5 l' w/ l* g! @* ]4 E
[WJ2440]#
' ^/ f; A5 u5 |& D; v7 U( y$ }( {% V& h# U1 ^8 L; o+ Q0 x2 r
7 e( l. P# _! a( e8 ?1 A6 A6 {
) n0 h9 V+ t1 Q2 i" U
! s3 t8 X5 r8 g5 g" m

该用户从未签到

3#
发表于 2020-4-24 15:11 | 只看该作者
初见linux字符驱动

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-25 23:07 , Processed in 0.156250 second(s), 24 queries , Gzip On.

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

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

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