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

初见linux字符驱动

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。
5 R+ s  j5 l% H$ N) S# C( M7 J
( n* k$ F& ?, o4 M这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。
% ?/ q3 v. k/ S
6 F4 N: y3 e0 Q* R# R, O7 M- w/ M一、字符驱动框架" O+ j5 ~0 U9 K

+ Y( ?$ p" F' j  l------------------------------------------------------------------------6 t4 S9 N5 w1 j$ C2 I# Q
3 n, X. X! X: f  K/ x, _; ^; i" {
APP:     open               read                   write' j7 U; y% d+ P( X5 A: k

: _% T  m, ^1 }, j------------------------------------------------------------------------& q3 d. n; A, V3 m- _# c) s

0 h. q* e; ~/ K2 F$ @* t7 xC 库( i" @. F  [" z. y+ `2 |8 M

. J* |% ^. A6 a2 K9 h- x------------------------------------------------------------------------  M3 n. k) _3 N0 }

# n5 d" l4 u5 e! b# S      system_open    system_read       system_write; w3 h: P, K- c/ R4 E- @
6 x( a* n3 y5 u5 Z* k  X

& S8 O+ \  M4 e2 N( z! p: ^6 F* A
------------------------------------------------------------------------& ^5 d" M( V' x' C- [; u6 ^
8 [0 u2 w, S! t5 }* N" ?' B
KERNEL:1 Q* k* u2 |5 B6 F

2 n4 X; F  o2 i- t2 W6 Z, J. m' Q      led_open           led_read               led_wirte6 ]* m  s6 O: k! L" Z* T
, l* k# w5 `+ t& A2 c
------------------------------------------------------------------------
% F% B% n8 ?0 B) Y9 ~. ?. Q1 v( E# I% v' R$ O
  r# x* k9 n& Q+ j9 ~' S

/ v6 [/ H; B1 r问:应用程序open如何找到驱动程序的open函数7 Q# j. \0 L4 k7 E
& d2 W! w( E* i3 ^
答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
' {0 E$ W* u4 E, b/ T# O
) z) I* T# f. `. ]问:通过什么样的方法来找到驱动程序的open函数
* d' j8 ?8 T1 v5 }, z
- R% [. j3 C: d5 U9 S: z! `5 U% }答:通过一个注册函数+设备节点4 E. G. Z. x: E5 J4 \8 b3 v: }8 r

0 v3 D2 l& T' R* e$ Q. `3 E7 N注册函数如下(旧的注册函数,新的以后再说):
5 a% n; B- J" C9 S- V5 T' z4 j8 g
( Y, Y  l; N/ k; r* y- qregister_chrdev(unsigned int major, const char * name, const struct file_operations * fops)# y7 [4 R- G8 ^3 k" G
. O( Q3 `) z5 Z9 O+ z
参数1:主设备号(重要)
9 H9 @& r$ J9 m. |/ E. o
4 s8 H; A- S; Y5 `* H参数2:名字(不重要)
- X; F9 ]* V+ j# m  v7 m! X* D
" T1 r- X5 F! x/ z参数3:file_operations结构体(重要)
( m5 O" \8 |7 t/ E0 k# R8 F; c  o. t" Y# m7 t
设备节点:9 r4 l0 Q* g- Q1 K6 }
3 X3 X5 L+ [: A9 v% e- D
可以手工创建也可以自动创建,这里暂且只说手工创建$ Y* x2 s4 ^8 `  x! B
2 v+ J* u. I% X
mknod  /dev/xxx  c  252  00 ]6 I2 D9 x6 @4 ]% w( b" N* A

, w! N6 }, a7 t$ i0 M$ a9 C具体什么含义,我就不多说了,看视频吧,很简单。( W- m" {3 I! W2 \  E+ [' R& ~
- S9 o" \% |& {: l1 n- Y

, q3 R  z: r# [* g  n0 V& Y# l# ^2 k
问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?
5 Z$ Z$ P8 v! c3 @4 ?
: |  R9 l4 @. c2 I1 Y答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。" p0 Y' y1 R1 u1 y# v6 G3 z5 e1 Q
4 f* v" @1 Q& q; e  C
例如:module_init(first_drv_init);  //用于修饰入口函数
6 y, u* J2 W9 J" U
* k: @+ D) r! z- e自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。7 q1 i8 L1 Y: f. T0 Z7 L

4 t7 p+ E* i7 R; X4 y例如:module_exit(first_drv_exit);  //用于修饰出口函数
; J6 U: p5 ^& J$ p
9 G. W0 k; h, ^4 P: [
) V8 U" Q/ x4 c0 C* g; D* b# \' \0 N9 a" N
驱动源程序如下:8 ^- V% j& R! Q. @, f/ Z
/ B& ?8 e* r3 `6 R, B
. W! N. u4 v" B; a; I
#include <linux/kernel.h>
! R% X' v& @6 x#include <linux/fs.h>
+ S7 i4 a# X1 D8 b#include <linux/init.h>
! w. x3 G( z3 e! @4 p4 p6 }1 o#include <linux/delay.h>
8 v8 T% Y" P' _8 {) \6 L#include <asm/uaccess.h>
7 P5 p. k" w5 M; E% I#include <asm/irq.h>+ I: F8 P6 ?* G
#include <asm/io.h>/ d6 R" g7 i9 |" R  B8 N
#include <linux/module.h>
4 K% D/ q4 Y4 n- D& G6 e! n3 {# v: s. e: g3 X
: _" z2 q. {' s+ a3 j4 W& D* Z  j
int major;2 A3 z9 o1 v5 S  h6 V# X5 \
static int first_drv_open(struct inode * inode, struct file * filp)4 x4 o+ ^7 m8 J; E3 l
{
5 j, J" A, q8 h0 T+ O$ A; o        printk("first_drv_open\n");
6 |, i- N. k  G# w: h+ ]3 \  C  f        return 0;$ e. ]1 k1 i& a
}
$ J- `1 l' H  ]. k2 h. x) Qstatic int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)6 Y$ t) G9 f9 M+ _" D1 V
{7 j1 H" H* V4 F1 {/ w6 [2 M$ U
        printk("first_drv_write\n");
# }' d$ }, \2 \) q& u8 Z        return 0;* _' f8 m' }- l# K- ]8 g+ i' _5 w" q4 Z
}9 N1 x6 `* C9 Q! T
. ^; a3 s7 ]+ \& G. e
/* File operations struct for character device */! y* k) w6 q7 l  M9 b9 n
static const struct file_operations first_drv_fops = {, ~$ M& o  _! o9 h' r( B# y; u
        .owner                = THIS_MODULE,
6 L" i) Y- a7 ~' ~6 K! _9 z: b        .open                = first_drv_open,
% q. `) X$ K0 \( D1 I        .write      = first_drv_write,2 j* `, x. W1 D; d
};' @; N) ~. }# k. r, b/ p) H. c
6 C+ n7 a) I5 n5 s
/* 驱动入口函数 */% h0 a* [* n3 C1 \
static int first_drv_init(void)
( o7 Z( M: j1 a2 m0 e' k# E0 h{( E+ ?& [: t4 f% |% U" [/ B
        /* 主设备号设置为0表示由系统自动分配主设备号 */' B8 d* z; c; J; U( G, v
        major = register_chrdev(0, "first_drv", &first_drv_fops);6 f: l# ]+ U% P' _$ V( d
        return 0;
& N( u1 ?% l3 A- u( F# l}
/ _! }) G1 k8 x& A4 v* F: ^3 f5 a- H1 C- O8 v8 ?
/* 驱动出口函数 */
; z, k! b& C9 Q9 astatic void first_drv_exit(void), P  Z( c) I6 S3 H
{# ~. |6 U3 h" h' l2 l
        unregister_chrdev(major, "first_drv");
, u3 ?  Z1 d9 M+ \, o+ b, G3 Z}
! _8 L7 [' {7 G/ X6 j+ B! E; O1 A* U; P; `9 t5 Q" g, M' T4 E
module_init(first_drv_init);  //用于修饰入口函数8 ~* u, {  i1 u
module_exit(first_drv_exit);  //用于修饰出口函数       
+ E& A. I( L: v7 \# j3 l0 G
6 u) d4 E3 j1 }+ s1 dMODULE_AUTHOR("LWJ");  I' U& o) C" Q: |* `  ?
MODULE_DESCRIPTION("Just for Demon");8 _2 ]( D- b3 x( T$ \. o. R- Y
MODULE_LICENSE("GPL");  //遵循GPL协议
0 \  t' I, Z- }  a% y2 }3 i% ~; e5 J  N- U1 @" ]$ T& I
Makefile源码如下:! i0 U2 q: p# h' `, m! [2 w

8 f; i: `+ t1 x7 L' F5 lifneq ($(KERNELRELEASE),)- j* N1 z8 y2 _  m" E- q* \
6 Q3 J1 A1 i$ Z6 V9 E. f
obj-m := first_drv.o/ k  \+ Q/ W, H$ s5 ?7 u
/ V2 p, D6 y  x: O# t1 M
else! X! n$ b7 T/ n( V) Y9 g6 G+ x' n
        0 B! s3 \* B* M2 `  [% b) n
KDIR := /home/opt/EmbedSky/linux-2.6.30.4* W8 T1 A% L" E- p" s& \
% b2 k4 E, D( B# g
all:+ x6 h/ h$ S/ N/ H  E
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
2 F. E2 z, {) l& W1 R1 a7 |clean:; x( D; y( K: Z, s4 [9 a4 M
        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
% e- n  [( C1 I" ^
, a3 w6 R. t% O+ i% ?- rendif, q: \! I+ [5 [7 }) W5 d+ ^

- E4 A! m9 ]+ N+ F) j+ V# m' ~测试程序如下:3 z) x8 ~2 a# l& m7 U% u! w
) P0 G! _2 i; }. s$ ^
#include <stdio.h>
6 D. T6 @7 t4 |& \  T#include <sys/types.h>; A: q0 l4 [5 T7 F$ @
#include <sys/stat.h>
9 x: H) r- O- L  W! Z#include <fcntl.h>: R$ I( O# M% ]& J) }
#include <unistd.h>3 d7 f3 o$ W' ]$ ^$ Y+ k

0 C- F: N$ I' F# I" |int main(void)
0 S- k1 A8 y- ]. z: h$ J5 P4 `: u# h
{" j' U( h# I) a$ h% X- V5 }3 e
        int fd;# w6 C- k; W& L% @
        int val = 1;
1 s- S4 y; \' |6 N' V, F        fd = open("/dev/xxx",O_RDWR);' P9 O* M" R9 j3 `' S
        if(fd < 0)
! }7 \0 n  d5 R9 t        {
3 `, B5 E0 ~$ t4 {                printf("open error\n");% X0 O2 @0 S  v2 q# _2 f& X
        }% p* M0 v/ g0 e: L0 B1 S. [
       
2 T- ~& `# O1 j/ v- p& L/ k        write(fd,&val,4);
7 t  ~, h8 t( N# @5 Q6 C+ S* M( L/ j3 F        $ l) Q; k- B) e) z" u% `
        return 0;
( _2 a- h4 T" `) G5 {8 I9 ?}# j+ ]& @' T% F! x9 q) H0 o) Z
& j* d0 m- A9 q5 C! v0 e
开发板上的测试步骤如下:
& S' w0 G( J, ]* r0 m. ?, w% J5 }" \6 a+ q- B1 l7 U
[WJ2440]# insmod first_drv.ko
) g5 s, A4 t' }8 k2 g[WJ2440]# ./first_test
8 Y: P) h- I* L5 |) `& w6 wopen error
+ p8 x# t! H; g) Q! M/ Y[WJ2440]# cat proc/devices 6 M7 c4 K+ T' N4 {0 A' |, w
Character devices:% |* r2 q+ R: l# h8 a
  1 mem
% [; J% ~5 k0 H  4 /dev/vc/07 x( C/ u  x: T& m+ m
  4 tty
+ {/ s- o' `2 v. Q: k0 p$ h" Y+ ?6 B  5 /dev/tty# m+ g6 {! ?: y0 A' E
  5 /dev/console5 y# v+ {" ?/ K' A0 h
  5 /dev/ptmx' C- S0 N) }* m. s
  7 vcs
7 @+ f& K- L- {! A 10 misc7 x5 b) N- F) X4 u$ ]0 l7 P
13 input" ~" l" ~, u& d
14 sound
% U+ }6 g* K  ?, ? 29 fb
+ P6 L; g; X, j3 I- c8 m- j 81 video4linux
( j" w# a  {* J$ E: Z, u 89 i2c
9 B3 f$ P: r# m' ^8 u$ s1 e" e 90 mtd
/ u8 x% W5 K4 L8 l& ]1 h6 ?116 alsa0 f5 n/ A7 O2 s" C7 A
128 ptm
3 l* M6 k  I, h' E. P4 m6 M136 pts5 |( `& @1 g) q6 q6 `  t; d
180 usb
) I: N; T3 u: t0 O188 ttyUSB
! m, d/ F* S. @: |; j" Q189 usb_device
  t* O+ K% v% J3 Z" B. M" C204 tq2440_serial
$ l6 ^' H5 h- H1 C% ?6 X252 first_drv) C# d- r' u$ v0 O1 J
253 usb_endpoint
- s6 ]' X7 T5 W' t$ R254 rtc: m" g5 U3 S8 l: e. Z
  F9 r% ?" q, A
Block devices:
+ j* q9 t$ D. f259 blkext8 x0 p# a$ V, T, m, d; ~8 w
  7 loop+ h( m/ P4 \+ S7 `! F- W
  8 sd0 H5 b: g$ s" l8 C+ S4 s
31 mtdblock
7 _/ n0 m. O3 k% _2 t) | 65 sd8 }( ]) |, y4 k/ v5 @9 V% o/ ~
66 sd
' Q, J# h% w# d3 d# c& i- e: B 67 sd
* `& A0 ^. {' t* ` 68 sd, X0 D$ h$ s1 {
69 sd# H& \  B+ F  I1 ~' p4 M4 `
70 sd
1 k! ]  y" J2 `+ {  w* F& h0 g+ f 71 sd
2 K1 @8 Y9 h# m( y  ^7 ~+ R128 sd) ?' C6 R3 V' c/ ^
129 sd
: l; B  [$ Z0 f9 C! n5 _130 sd
3 Z( S7 a; \" L% K6 E1 `. u' B131 sd0 P0 q& R& R1 `* x6 P1 ?% W* |
132 sd' F  v' w# E6 }1 S' Z
133 sd
- s- Q% y: [) P6 h) Y8 \/ [134 sd
& a* d" |% R- O, K" [! m# i+ V2 t, C135 sd5 h, {" c6 x( @; w% D5 j7 Y
179 mmc. n  r- j/ e) q5 n+ L1 H
[WJ2440]# mknod /dev/xxx c 252 02 c9 u4 l( G& k6 J! A5 C5 \  L1 C) j
[WJ2440]# ls -l /dev/xxx
" M* Z7 a3 i; U3 s' Xcrw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
: l' ?* d9 h! l5 Q' T. e[WJ2440]# ./first_test & j3 M1 w9 `7 o- V8 K) q
first_drv_open& _1 p: v0 U$ Q6 n/ l) K& y0 b
first_drv_write: L, x/ s: E7 D! Z9 @! w0 [
[WJ2440]#
1 h( F: I6 `9 E' }9 k7 ~) X
8 Q+ w2 T# O! Q& S+ c; c: e& G, z9 e  Q" W3 `

# D4 n. A1 Z! g1 g: {; z/ t1 A
2 k6 s" Z' I6 X% t9 C  r

该用户从未签到

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 05:54 , Processed in 0.156250 second(s), 23 queries , Gzip On.

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

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

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