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

linux字符驱动之初见

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。) h: L! A! X" V+ P

& d4 P7 H8 y% v9 p这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。' B( n: w5 s. q4 a) R

" |- Z6 E) ~) ]: t% n4 x一、字符驱动框架
( j6 o7 }1 n/ M) O$ F
, `, i+ Q0 r! G4 j5 i------------------------------------------------------------------------# }! H( ?3 |+ p* U

, ~. }; }3 a0 H/ `* }8 rAPP:     open               read                   write
! O+ X. z2 C5 n5 n+ j
' X$ {3 W. X* N( T& m------------------------------------------------------------------------
) H  X, r( {6 h: S- x9 z7 k
( |7 h# h" T# A. _) Y7 l7 N/ m7 GC 库
/ {- ]( v0 T0 D# M
3 z, S# g8 H- t9 r9 [- }; @) F------------------------------------------------------------------------
  a7 V! [- S" O+ F! }9 {- n: B3 w; @/ |, W0 O& v9 o8 O* c9 S
      system_open    system_read       system_write
" i& d# I, t2 [+ }' ]) ^+ z  r9 C6 A& j' l

. ]: v: w- }3 J1 Z! R2 o
: m$ Y/ I9 f% W8 y------------------------------------------------------------------------( T, {  E. k  C6 v  C. z
0 l+ u8 u  G+ c: B/ U
KERNEL:
) n3 N) d8 c: u
/ `3 y+ D; M* a2 E0 S- t- h      led_open           led_read               led_wirte
2 m9 k2 D. w9 T3 H/ _  X% X4 N, m5 D0 y, J. c7 w7 B" a
------------------------------------------------------------------------" O: l5 m/ d. i* i1 |* e+ p

! J1 H4 N* [# \% @0 R
9 N% Z7 R' F0 X' C0 @+ S! Y4 v* _8 x5 E+ m* a
问:应用程序open如何找到驱动程序的open函数
. u5 h. G/ t0 i3 C7 J8 D* G* a  y" H# g4 w9 W( h: A6 B8 b
答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
2 B, H4 v# C. h- S, }0 c& H2 @
& ]! f& x! O- _8 u/ ~0 n问:通过什么样的方法来找到驱动程序的open函数
' R& [8 j% `+ n2 h* ~
+ f! K% P) j/ Q4 Z. N5 J答:通过一个注册函数+设备节点
  X1 j9 Z* W7 z/ r. H$ Z) ~  ]; t& t
注册函数如下(旧的注册函数,新的以后再说):
- e/ w) J( E  i/ ?' Z  q/ p! p! L8 U7 s5 F, {* w0 D2 l; ^' N
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)$ V' f: L; x& S5 I

3 l; x3 k! P/ F8 N/ ?( Z# `9 \参数1:主设备号(重要)
* O7 Z+ l( n0 E' d  N4 c6 V3 A. H% F" ~1 f  G% R9 R+ M  T' F
参数2:名字(不重要): ]/ t, {3 n! w6 [. t( |
2 _% v5 f* T: u9 Y
参数3:file_operations结构体(重要)
" Y7 p; \0 r( _1 ]7 p' X( V
/ `4 Z0 i" |' k2 B设备节点:0 L/ @3 n  n# C4 [$ P0 |

; _- \( H  q: {可以手工创建也可以自动创建,这里暂且只说手工创建
) A1 V, ~' l" U) ~
; w& n; e4 N  f) n  x" C* {mknod  /dev/xxx  c  252  0" E) _( ]5 x% d  M% X

* {! r$ ]  A+ J+ z8 J# H9 w具体什么含义,我就不多说了,看视频吧,很简单。4 U$ `3 a& i2 y5 a" y
3 j8 K) b- h3 F8 _# J" o4 T
& H* z  v5 k9 y: `
) v' U4 W( B. o  S) W3 ^
问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?$ U" J* Q. l3 M- _$ X8 i: u" D, V' b: {
3 T6 c& K5 W% l0 ]: g& e* D
答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
, J- f9 G% n" R/ o( e& c! `$ o0 P  e2 W1 Q" n
例如:module_init(first_drv_init);  //用于修饰入口函数. D  y. j5 U9 A- \6 w7 y5 O
) b; K! q  Q4 @* ~$ n
自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。7 G3 t6 {% h5 `' v1 p  n# z& P1 H
+ n7 I% `/ M3 M; J( j; {3 O& P
例如:module_exit(first_drv_exit);  //用于修饰出口函数0 s/ u- `4 p$ ]: u! Y7 v/ [' G

1 X% w1 ^% P' X( u: U
' @  z* q( i  n  {! f1 W# a% P4 I$ U, Z
驱动源程序如下:: A3 h; e) L+ b4 S; Q8 h% ~, s
! D8 z; V+ a. D
) j+ X# ]& d6 |- G. Z9 f
#include <linux/kernel.h>6 w- v+ j0 d9 Y0 p. R+ g1 u
#include <linux/fs.h>, D4 C1 z/ E6 U1 G1 R, C6 S2 K
#include <linux/init.h>, z% ~# p3 w; X5 y& A
#include <linux/delay.h>& @8 [6 m' R3 H. G  J. d1 \
#include <asm/uaccess.h>
/ Q0 M* |* X( W. ]#include <asm/irq.h>
, H5 `8 M: ~( w4 A) [6 t#include <asm/io.h>4 j" d5 Q. s9 O9 d+ k
#include <linux/module.h>
' \1 w9 U, X  d% B, ?. B
) }* z/ m& x* I
% G6 z- [" ^# N7 @8 Xint major;3 j5 l: t: B+ s  }  \
static int first_drv_open(struct inode * inode, struct file * filp)
& G- S. q/ {( G8 J{' v3 R: M/ ^4 e8 N
        printk("first_drv_open\n");6 X4 I/ q# c9 R$ p  |- p, e* r6 t9 h
        return 0;
. n8 z2 l5 _6 E  y) |4 P}' P- I) R) j& R
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)0 U% }  M: q& ~4 z4 _
{
$ F. O- i; s. c" q        printk("first_drv_write\n");
) m& ^/ P$ V  x! m, u+ ]        return 0;
6 }/ X" _% U+ B" h7 @}, V  p# L! z' s; i2 P6 J

+ P( N" c, @+ E) o! U/* File operations struct for character device */
% u; t) W( a: @$ q0 s& Q- f' ?5 w! pstatic const struct file_operations first_drv_fops = {8 s) S/ I) m7 w$ B# Z5 t  S6 y  j# j
        .owner                = THIS_MODULE,! J( m1 l8 i" b5 w- N  B; X
        .open                = first_drv_open,
5 S8 W+ X+ J3 e9 y        .write      = first_drv_write,  M1 G, s' v9 \; [5 g
};# }3 T( y& F; N5 P

7 i! X- `5 T8 c/* 驱动入口函数 */
4 w; M2 \3 j, X& |static int first_drv_init(void)
2 x( U3 @4 D; ~$ I( c  P{
9 F: z: T+ u( u        /* 主设备号设置为0表示由系统自动分配主设备号 */; w7 ]) Q9 Y: F
        major = register_chrdev(0, "first_drv", &first_drv_fops);8 g" k& M/ D: K3 A& \6 f& Q( s1 O
        return 0;
. K/ A  T# Y" p}
4 t! V  b  b# X7 N  V% b4 V. R! @, p3 h6 N8 U
/* 驱动出口函数 */1 {1 |: O3 _( Q
static void first_drv_exit(void)
8 ]8 K& s) \% t) a3 j6 b% o{- u4 {- C" @' m0 H$ B5 N
        unregister_chrdev(major, "first_drv");
& }. L3 b- K% S2 S( R# A}/ {3 I; S' B9 q# ?2 H% z# U, s

, E0 d3 ?! |7 gmodule_init(first_drv_init);  //用于修饰入口函数
+ T: g4 x' C5 Dmodule_exit(first_drv_exit);  //用于修饰出口函数        9 z( x6 R9 W/ S  ^; c6 a: g: k

8 J! Y0 `; _6 ~' O2 Q7 e+ ~MODULE_AUTHOR("LWJ");
: P- `; C- q& P: [4 BMODULE_DESCRIPTION("Just for Demon");
' `% U3 X% D" \MODULE_LICENSE("GPL");  //遵循GPL协议
" T' G: n" p9 ^7 D/ A% H! B- P4 q- p+ S8 h
Makefile源码如下:! ?1 b' @7 L; |3 l* b/ d  T7 r

; Z# R% F: K# g* Aifneq ($(KERNELRELEASE),)
+ }, s4 j- z$ d0 V! G& }
+ k' L6 f7 F% }+ M5 L# ~" b) _obj-m := first_drv.o5 I2 D; D" s4 i% g+ H2 @

8 s3 i) V+ a, @2 J. d2 z2 T3 Melse
0 w" o- Z& X. U  X3 P- P* |, e        : e- B. E, R$ P) b5 n' x' P: g9 N% ~
KDIR := /home/opt/EmbedSky/linux-2.6.30.4* k) W: r+ n2 v& t& i& J
0 g  Y$ F- u4 {5 l
all:, z4 x& d9 H* s2 H
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
2 Z/ v; F+ \6 ^& t6 O/ fclean:
$ C' I/ o' @, ^6 h: L        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
" x6 K) J$ }7 `! R7 g% {9 g7 y) E5 `" D& D- {/ x: |
endif
7 I3 Z, d/ X& Q8 T$ K: \
2 F2 v! n: S5 x- @1 I% l测试程序如下:
2 q9 ?* J* q! ^' z5 b- R) h) m2 i! O3 }; \" V
#include <stdio.h>
; d& D7 y& ?3 A9 z- H- z! ~1 d2 Z( K#include <sys/types.h>
6 [8 l/ R+ E2 M) P#include <sys/stat.h>
9 \4 v7 E8 I7 I7 ]7 G#include <fcntl.h>
* E9 G9 C2 X0 Q3 o, X' w6 F3 @#include <unistd.h>
, }. G: h7 h, E' S% ^1 `: r
1 ^, Y$ N; i& q% C7 m6 }: y7 Yint main(void)* y) w! f  o5 E- H' s

' j% [2 m3 {9 ?" Q{
& q  G. L! x& \$ \        int fd;0 I) x9 w* |/ Q7 ?
        int val = 1;! {/ x2 S( h. i7 Z, Y9 e2 t' s/ S
        fd = open("/dev/xxx",O_RDWR);
, p2 n! @, v# a7 y% m- Q        if(fd < 0)) I) @4 }9 E- X; C6 I
        {# z! k: B& B% G
                printf("open error\n");
, Y! l7 i1 J0 ~2 W; Y% C- M+ q# O        }; c8 }/ O* {( k7 y" {- F4 s0 Y/ n
        - a2 b$ ~7 s2 X2 r* ^  p' k
        write(fd,&val,4);
% O7 {+ }3 _8 q" V& J        / d; ]5 w4 l8 O1 W: I$ ?, a" G
        return 0;4 n; l( X5 f% b3 b1 h" m
}
: [2 c* a1 Z" J! A
  A8 P' q- _. C$ q. V# Y* g4 w开发板上的测试步骤如下:/ V3 @" M/ p' `
" M1 j- v: f$ c' Z
[WJ2440]# insmod first_drv.ko : _- L, C& j" e9 F2 r0 {/ X- N0 V
[WJ2440]# ./first_test
4 W, X: j0 X4 bopen error
, U# L. z1 l% p% W5 S3 h7 ][WJ2440]# cat proc/devices 9 l  {( W0 T5 W/ e: V
Character devices:3 ~% Q- M8 ]- X9 Z) f
  1 mem
# J. d, O7 K8 `: n5 N" q/ p  4 /dev/vc/0& v! ?6 o. h& T6 J  D
  4 tty
2 z. p8 p8 K3 j* H% g  5 /dev/tty% y, g% t0 m" M- d% x  M
  5 /dev/console
0 j! c4 _% d- b! O  5 /dev/ptmx4 Z5 @5 ^# o$ N  v9 U
  7 vcs+ U4 X5 V; C$ n8 G
10 misc
6 ~+ P- F6 B! I* K7 U6 I3 ?1 J% ` 13 input/ M0 x+ b; ~3 i
14 sound& v9 M# \7 q6 X% w; _
29 fb
) |) o$ q- r. J5 b$ L2 Z  |1 M 81 video4linux
5 ^6 |- o% p4 ]* X) O1 {2 d+ A1 a( i 89 i2c
$ V4 T$ V+ Y# t$ g: B4 c! r, E 90 mtd
" q$ T3 x# y% S% I; k* I116 alsa
& Y0 I; X8 Q* Q$ o2 K; J128 ptm
8 s, q2 H8 p6 j8 O136 pts
! P5 Q. ?/ b3 d- J: b180 usb
; t8 t0 `5 ], E! `1 Q. |6 }188 ttyUSB( [+ o; ^2 \, e: Q3 _
189 usb_device
- A, e, ~4 G& m6 e204 tq2440_serial
# L8 T& W0 K$ Q9 a; T6 D; e% T4 A252 first_drv, S  I1 i) h, n$ a
253 usb_endpoint8 g3 G0 h1 s, o) d' S! K+ u
254 rtc
2 w1 F3 p+ l) l* E! Z* R; g
8 R; a" N3 o# G* `! c9 ~2 E) A+ R" PBlock devices:
! X4 W* A& U* h1 z259 blkext
! l# s- V! I( l% F- o  W  7 loop, x1 a) B5 H% t/ v; i$ N  w
  8 sd" b" z4 O# z# U4 w; q% o
31 mtdblock
/ O. c+ X. [2 D- ~1 N3 N" K9 \& m 65 sd
5 Y9 ]) i. T9 r' V# {9 r 66 sd
- u$ H. `% Q  i6 ` 67 sd6 F( E( f/ A  {
68 sd
2 ^0 E, e) n" q# ? 69 sd. D, i- I* ^2 k- ^3 C
70 sd
% b- \# V( ~, A- G! x4 F9 P 71 sd) T. x" m2 r, n
128 sd$ h% |1 n) s6 S) C9 _7 \- u) A
129 sd5 G4 n5 U+ b1 ^
130 sd' F, t# E) h8 ^
131 sd) N! A; f0 \0 Z
132 sd7 s$ P/ E7 d" _7 o7 M4 w/ o
133 sd% T) i/ G9 @4 h
134 sd# \# A% a4 l8 L
135 sd
! v/ V3 ?* L% B5 k2 Q& \179 mmc: x$ ]4 K3 Z, u% r0 C  O
[WJ2440]# mknod /dev/xxx c 252 0: [' [8 S7 v7 T, K4 c' Z( {/ ]5 P
[WJ2440]# ls -l /dev/xxx
, }& ~. m) l" Rcrw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
+ R# K% Y6 E# l( J+ ~. o5 y3 q[WJ2440]# ./first_test 8 c; v- _/ E( F6 }* w9 D5 D+ [
first_drv_open
/ ?( Q- x) r! b. M2 Ifirst_drv_write$ ?$ i- _# E5 e  s- {
[WJ2440]#   H4 i6 t3 g, K
& B  q* `% G9 T: ?' \8 ]
# a$ O" M9 W9 p2 t0 n8 n

" Z, e8 b# f- E3 l

该用户从未签到

2#
发表于 2020-4-27 13:22 | 只看该作者
linux字符驱动之初见
  • TA的每日心情

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

    [LV.1]初来乍到

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

    本版积分规则

    关闭

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

    EDA365公众号

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

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

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

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

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