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

初见linux字符驱动

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。
' x3 Z/ f. v- b0 _4 Q, l
4 J5 t, a+ l  _# x6 a这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。8 L* J# W) y" |: A6 A

8 E( G2 k& m, H2 M一、字符驱动框架
( C5 ?3 m' G- r# I& U: j1 r
) g6 e5 W7 V, |9 F# m------------------------------------------------------------------------
: J2 m, k9 D, B/ Q, W$ j) A5 {$ h" Y9 y5 J) v5 m: d+ C: T
APP:     open               read                   write' Q4 F; f; t0 R) N

# t8 l; p/ |* b2 Q7 A: s7 H------------------------------------------------------------------------
: n6 x& ^, Z0 x! _! v+ j1 j+ y' R# |' c; R8 {8 M2 G
C 库& ^" L' k9 L( b- t7 M0 @1 U) S$ E
5 n2 g/ _. F  L
------------------------------------------------------------------------
: h  l* R1 I; X7 A! ^, U- o, |( r* \
      system_open    system_read       system_write5 U% q) V$ d7 P, m

0 L: i& o* |9 Z9 B/ o& D+ Q
# }0 @7 `- r  }* `# e) m# @
  g. r, U7 K! e------------------------------------------------------------------------
+ `4 E" t$ L8 l3 `/ F
; n! ^7 Y8 c! y* t+ P  mKERNEL:/ C; x  j+ {. C( X& ?# H

- k3 b9 U& F: H, b- I8 C  J5 O      led_open           led_read               led_wirte1 C. y3 j+ H. W/ `# p, ]5 ?. \
' ?) b; Z% c, E
------------------------------------------------------------------------. Z9 w7 y7 E; u: x! g0 f# V" W6 T& U

  g. m# [! C  S! |* x
2 ]. e- h- ~. p8 v8 @9 b4 n1 }; x+ J2 [, J4 g1 r
问:应用程序open如何找到驱动程序的open函数
( n$ C1 u/ A# @/ R/ t, z2 {
; |4 }/ h8 r9 P: [. n7 m/ w2 p答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
; l; m- E& s5 F2 U9 g- Y( m& e$ O7 F1 A5 M
问:通过什么样的方法来找到驱动程序的open函数
* |, g- @# H' Q& p& g+ ]* F) ^) X- }
/ {! O" A8 d* l, C- C3 }9 T, z, R答:通过一个注册函数+设备节点% t" ^3 D8 {; W9 G. ~
7 U: D% `9 y* k3 m  l$ i
注册函数如下(旧的注册函数,新的以后再说):, A8 X. s+ M: U2 b9 ^* Q, M* V
- g# \3 o7 |+ Q% j) P6 @
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
5 K7 g: c$ [" x# F. c! ?% m* E3 Q+ w0 {( v! L0 n9 Z) Z
参数1:主设备号(重要)+ c- d) B) B" u6 ^0 ]& G/ \) h
7 x! Z6 W9 z( o
参数2:名字(不重要)
5 s. c; \/ f) n1 o* X
( u& H2 F  ?7 b, \" Z, q2 l; e! e参数3:file_operations结构体(重要)) l: s. e1 X# t

  I4 w) F! d" m+ S4 T6 d+ w# |设备节点:
; g4 s% O- W" L8 j4 o
$ P% S$ P2 B5 m9 a# v可以手工创建也可以自动创建,这里暂且只说手工创建
; u3 n& e! S; k  U7 t, Z$ }. U: A- K0 Z# O. Z6 }
mknod  /dev/xxx  c  252  0
1 Z: z( h7 v0 X( X/ G: z% Y0 M( C
: q) |7 {: E. Z# S具体什么含义,我就不多说了,看视频吧,很简单。; I9 ^6 u  M. Z" f. a- ?
' q) M8 {# v* L2 P

+ h$ p+ e# R. F( S4 J
: Z" s9 J/ o  O* W4 ~问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?, q4 _# o- ^" M% a

8 P: @* v3 d1 `1 e3 t0 v* i答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
4 i3 t; o6 A+ p
# R; y2 s5 G5 u7 p例如:module_init(first_drv_init);  //用于修饰入口函数$ S2 o' r# [+ o2 W
* @6 b. B0 A. r4 O3 f2 w# v
自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。
/ L6 e7 a. C! s5 q, T3 l3 u% Q. `- P) J, n- W' B# d  ?
例如:module_exit(first_drv_exit);  //用于修饰出口函数
7 U+ N. J1 G4 E9 R8 q
, T: b2 L# U; z( K: [, M1 N8 A! |
% U2 E. V+ O% R3 s( i: G; f/ [( n# d8 V
驱动源程序如下:
. [2 @# q( H+ l* X" ~0 y
, p' J: r, a4 d. O$ c; ?, x/ o  P+ a
#include <linux/kernel.h>
, c- T9 h, t' Q% V4 ]) _: r: U#include <linux/fs.h>" d1 N( G/ u6 r. k
#include <linux/init.h>
0 i  E, Z+ e' E, n7 o9 F7 ^5 d: ^#include <linux/delay.h>
4 z8 M  K7 K$ E# C  ^#include <asm/uaccess.h>: ~/ \0 w8 O/ |: Z; `3 F/ U
#include <asm/irq.h>
( W1 t5 Q) X- V! }5 \! ]#include <asm/io.h>- x+ A. c) j# O8 X
#include <linux/module.h>+ Q) K: d. P5 I$ I$ N" \" @# k: F
9 q$ v3 L3 E: x, C( r* K

4 I8 |2 X0 M4 w' {: a" g6 G: Fint major;
) D3 m( i1 H: l$ A1 A; istatic int first_drv_open(struct inode * inode, struct file * filp)1 x" p; y4 W( q' S$ ~9 V
{! o5 r2 k. `4 d# i$ S
        printk("first_drv_open\n");  a( E3 T  C( d/ p  [6 o
        return 0;
- j+ h9 j$ @1 P6 s}; i* g1 c3 O1 ]* \+ T) o/ q
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)% k: @8 Y' [, q3 }; |
{
" h7 V  ]  n- D: F" L7 {        printk("first_drv_write\n");3 V) C! w8 u" Z: ^0 s- U8 r
        return 0;% |8 o1 Q; k" E
}0 G6 j) I( j) i# [0 Z

& P: \9 x+ b- r- d/* File operations struct for character device */% v" H! F8 M; }& k# u5 y
static const struct file_operations first_drv_fops = {
2 ?: u" Y, R: G9 X  ~        .owner                = THIS_MODULE,
1 y% v: M# |: m        .open                = first_drv_open,
; D; ]' }# _# |; ~; M/ ~5 z        .write      = first_drv_write,
, }' x. {4 ^- Y0 S: S};
* F9 x) v6 ]" K% H/ k: m- e+ G2 G# r
# G: Y/ S: n: Q  u/* 驱动入口函数 */
$ s* Z8 E. y! {! P/ }# Pstatic int first_drv_init(void): p+ ^& N0 x4 c
{
/ I6 l" j2 U. a5 K/ f  m4 ?; w- V( Y        /* 主设备号设置为0表示由系统自动分配主设备号 */- Q. G# e; k2 Y( y
        major = register_chrdev(0, "first_drv", &first_drv_fops);
2 x7 E3 s9 h! Q9 G9 B        return 0;6 }6 J5 O5 v( ?3 X1 |# m& Z
}
. w  ^. ^8 p! [$ D/ i& n% P
$ }7 m# ~0 y& `2 Q3 m5 ]. h/* 驱动出口函数 */
! x% S4 p; k, o6 i' rstatic void first_drv_exit(void)
, |- s  e% X5 _  x8 i  N0 E{
0 ]; p; p3 ~8 O. A- z* g        unregister_chrdev(major, "first_drv");  a9 M- Q  [3 Z
}5 b6 k2 |1 K  j/ \# X2 f$ U

) w" z4 p6 ^, U% fmodule_init(first_drv_init);  //用于修饰入口函数: e7 J7 Z' i( i( s
module_exit(first_drv_exit);  //用于修饰出口函数        ; M2 D. Y) n3 {4 ^$ o% c* F
9 X( r  {! m: ?% S
MODULE_AUTHOR("LWJ");4 \: S; G2 M9 D. Q; B! C3 ~
MODULE_DESCRIPTION("Just for Demon");
/ M3 m# z2 D& QMODULE_LICENSE("GPL");  //遵循GPL协议: C+ t, Y$ z6 Y! g

6 D. s3 ~( ^, [8 h/ q' t# w! L9 NMakefile源码如下:4 _. N% v) Y: D

# U  k3 K0 ^2 R" f' Mifneq ($(KERNELRELEASE),)
: e/ q8 E  R$ A- G* S# O* e! {( n4 w1 P+ ~" i! @. D  }& |) v; ?! o
obj-m := first_drv.o
& s+ x( C; `: V5 G$ Y5 G) L  ?+ V* f6 t9 H+ T1 {: _/ N" I
else# T( f6 l, L8 \1 |# f0 g
       
% w& ~3 p* I/ i7 QKDIR := /home/opt/EmbedSky/linux-2.6.30.4
0 i9 l8 i/ a# ]# J- p% p
6 }. H; I4 `7 T( j/ E! Iall:. ]) h, v& Y9 s* E6 Y- R8 |
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-, p# [4 O( |+ b/ E# t! t
clean:5 e% i5 L4 u. E" B
        rm -f *.ko *.o *.mod.o *.mod.c *.symvers6 h1 A3 K0 Q' Z  \+ n+ x$ i  @

7 p3 A  p# d0 P1 P# yendif# x3 v* ~- I% f% }4 e  }
! {. e  P7 a( t5 H
测试程序如下:
% A3 |  ]& k7 O7 L+ g% V
. K) J3 I% K0 t. h4 l#include <stdio.h>9 M* q% Z# k. E- M6 G
#include <sys/types.h>
6 ]3 J: u, A0 ?/ E  [7 ]5 B#include <sys/stat.h>
% T* h  [# f3 U5 b' j0 k1 k#include <fcntl.h>1 k) J# I8 I: M" e" x! ?; C( n; ~$ w8 Y
#include <unistd.h>
/ H. m! J& v7 b! O8 v8 q- q' Y; d; _
int main(void)! ?; |9 V2 [4 U  i" I5 l

" j% w- i) C5 v{9 U0 [( u0 |) g7 L( b1 x: u
        int fd;$ O4 Y1 \- Y; w0 [
        int val = 1;
4 C, A  p3 w, w: _2 _        fd = open("/dev/xxx",O_RDWR);0 ^: @' W) O* L1 c) ^$ V7 v
        if(fd < 0)
# D' m4 P+ ?+ h( n! D. T        {
8 L" T/ q: n5 O; O                printf("open error\n");
  F( r" i' l+ U9 n1 n  U        }
! X7 Q' q4 O  K3 G  `/ q        ' @: X5 }, k* V
        write(fd,&val,4);
) S2 o' `: j2 G+ i( e+ n        ( w* ~; _; w% ^0 T) \6 t
        return 0;
0 V# T8 i: i' w1 P- T; D+ \' {/ }; v}7 L- f. ]' w; Y& [) V$ Q# [2 O: G
9 ?: `' M0 b1 V) g7 K
开发板上的测试步骤如下:" v/ {5 _0 N+ P* c# D$ a* y/ W- s. M

/ P  b5 S; m3 S) F  m[WJ2440]# insmod first_drv.ko ( v$ [. T6 v! F0 I& U0 w
[WJ2440]# ./first_test
. z: s' j: X5 y( d# K7 H% |open error
2 a/ N) l- K# n8 q0 q[WJ2440]# cat proc/devices 6 V$ f! t1 l9 l/ E" J) T
Character devices:
" [! k4 f1 m1 `/ K. P& O# [  1 mem
$ \# H7 s7 h0 U; V% F* ]" e  4 /dev/vc/0) h' p" J( C- a  I( p
  4 tty- W6 X3 Q$ t  m0 S$ ^
  5 /dev/tty* x1 z; B4 }! b1 t+ |9 `
  5 /dev/console2 `+ e* R  V# y: |; h2 z
  5 /dev/ptmx/ J4 `5 G4 k2 b5 E0 B4 U+ v, L
  7 vcs% f' v, }. V# x+ v! G
10 misc5 o: D8 p2 z/ J. t  z
13 input  o6 j9 w9 O6 z4 [5 v# |" C
14 sound
& F- a( U# V3 u1 j6 }3 ^ 29 fb
; ?3 d0 ?9 `& X2 K 81 video4linux
! s- L9 \) v" P: `' e+ b9 `% S 89 i2c
7 L( q" ?# v7 [* K 90 mtd
* S0 |  V  \7 d. z116 alsa2 ^5 b$ z" o+ {
128 ptm$ H" F. J, C2 e: u- |5 N
136 pts
; y6 z$ R* F8 H- B180 usb9 X+ r. Y/ A; k5 Y' v4 w; a
188 ttyUSB. I3 a, V' C# Z' V
189 usb_device3 n8 W/ d1 T- O, [% t4 T. C/ A7 L
204 tq2440_serial2 s7 _; y; X7 D$ |4 ^% C
252 first_drv: L  i7 H: a% V2 p
253 usb_endpoint
0 [' i; _* }1 O4 v7 f% D254 rtc
9 @3 _7 b% a( Z9 P9 d6 T
' c# n( M& [8 e4 s* aBlock devices:
5 |; \+ T2 ~) i& F+ ~; C+ `9 W9 E259 blkext
  E9 g  o1 K1 b, e4 I. H: B5 U  7 loop
; b/ D: r/ `' r& E+ U  8 sd; t6 Q1 s8 p0 W5 ?. A
31 mtdblock
. r. R; z7 [- h: ^ 65 sd4 u2 A6 c0 `+ Z) ~) P- N5 c
66 sd( V) U- r" u! f6 n' _; D
67 sd3 ^' \" I. A) _: r0 d4 S
68 sd
0 r, S; ?& y1 V+ [: _/ m+ Z8 ? 69 sd& I) P; u7 v( F6 ?& ]' G, E
70 sd
/ e( D& R6 V4 w. D 71 sd& q2 F5 U( z" d; X  x. M. ^3 b$ T
128 sd
4 k# N/ m' D* h' ?' v9 }129 sd  a% r1 O+ d* z2 e
130 sd
5 a5 c- y; b5 L: D131 sd
8 s# I3 R$ n. t, w+ h2 E132 sd2 `% p* n; x$ @
133 sd
( U7 X$ Y  [2 w134 sd
& O6 g) \# I: @4 _" U6 S135 sd
9 u! j% \; h+ p179 mmc
  s- w" _& g% O" U/ D7 H[WJ2440]# mknod /dev/xxx c 252 0
- v4 Z5 Q3 N1 C4 f/ l; j[WJ2440]# ls -l /dev/xxx " d+ g3 m/ R9 N
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx$ H2 r( x1 V: R3 u2 |( m- `1 h
[WJ2440]# ./first_test 4 B/ N; c7 H9 I6 d: l! Q
first_drv_open% }, T5 ~) f2 n" G
first_drv_write
( f+ \) y7 V1 @  H6 S3 j, O. \[WJ2440]#
' B9 [( _1 ^% v/ m
  T2 r# Q7 |' m5 `" O5 ?
3 u7 S. a5 R5 |3 y
! r/ |' B! Q+ b& Z: {  B2 }& |' |: E' L& S2 Y4 W2 r8 T, `3 t

该用户从未签到

2#
发表于 2020-4-23 13:39 | 只看该作者
linux字符驱动

该用户从未签到

3#
发表于 2020-4-24 15:11 | 只看该作者
初见linux字符驱动
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-26 00:30 , Processed in 0.171875 second(s), 23 queries , Gzip On.

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

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

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