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

linux字符驱动之初见

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。! i9 q) I, K9 r8 ^
# ^7 o  X" s6 D2 s5 X" w5 j
这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。
5 o% k) Y/ i; u5 n! A; ]8 h) d
) Q. _0 |) [; f1 }0 q一、字符驱动框架, y2 t' g0 b' h% O* u6 [5 O2 e
0 L5 C; P5 z" b1 O2 F5 g0 x
------------------------------------------------------------------------  ]) A1 j3 H* i5 q9 [

" T4 M& V! B* [2 u" rAPP:     open               read                   write1 x4 [  H1 J4 N) y3 j
2 e7 R2 }7 C2 p
------------------------------------------------------------------------+ U  ^+ H7 W8 p: i, ~
1 m: @( m9 r" V9 p" B+ ~
C 库
5 q: [* _3 S, f! f# ?
4 Z% D7 I4 S' F------------------------------------------------------------------------7 ~# w5 l0 a# C2 _1 w2 |$ S+ ~

& `1 D! d8 G5 ^8 z. }/ E+ _$ D2 w; o      system_open    system_read       system_write
# |- R- V* s+ }' S# G
: I: v0 n! W! v7 F
2 o$ d  P3 ]$ x) }# F9 C- b
; b3 M2 s+ B% Y. M2 g* ^+ K- ]------------------------------------------------------------------------
- x9 r( w! l" c2 ~
  ]5 U" u8 `- B# S( j7 e% Z/ \7 fKERNEL:, T+ S& h% ]' e# O! C
) l4 E" g% F! m# |& E2 s( [$ g
      led_open           led_read               led_wirte
9 }: j( f: H* A, z# q" q4 d
# H7 l1 j* [+ q* Z------------------------------------------------------------------------
1 `! ?4 {0 H4 \( [2 [' a( `: ^9 q( J
8 s' u" l+ t6 s6 n' C# [

, j$ z& |! r5 N. ?  f0 f& N+ B问:应用程序open如何找到驱动程序的open函数1 }( f- o2 q3 |+ F9 i" A) F

/ E) }, ^$ ^7 C  N. z答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
6 I; P1 T5 J9 K) n0 }: c
, B2 p- i; x" K+ D9 u+ a问:通过什么样的方法来找到驱动程序的open函数- V1 q0 F8 Q7 C, k9 `) [4 r3 J1 U  U. ]

$ i0 [: e/ B) C/ u- D答:通过一个注册函数+设备节点/ o4 `& H; ~9 H/ b5 w. x
2 z0 v+ X! t7 G; b9 W
注册函数如下(旧的注册函数,新的以后再说):$ `) U5 }- l9 C* ^# v8 ]) J
9 M: b$ e/ W( z6 d
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
* E2 C4 Q9 m: u
- t$ V% J9 ^' S! E% c8 B参数1:主设备号(重要)
3 [# w: t1 T) g2 I7 Q4 G
/ _; p2 i! [0 i' h: i参数2:名字(不重要)) a* C" {9 N- H; r+ O! E9 F% \
1 F6 j# X7 ?) e% U( A/ Z- M
参数3:file_operations结构体(重要)' V% E* u2 n' V

- _7 R5 U" N  M0 |4 \4 v设备节点:
: F* ~& Y- d' M
- S3 s5 v& @; c' t. T4 H可以手工创建也可以自动创建,这里暂且只说手工创建, b$ {& T7 x- v" Z1 _
# }" A% r' C- d, K# L9 Y% c- X  o
mknod  /dev/xxx  c  252  0
2 X: r; O' @- {( K7 ~" p- e
1 d1 k/ @( G  L. u$ u3 }2 c具体什么含义,我就不多说了,看视频吧,很简单。
& k" D2 G* r, y+ G9 p  P) T- }+ X1 `6 m8 B+ ]
$ |" a( s% T( Y5 I3 ^) m7 b8 I% H, m

5 z/ f4 U: L7 q( q5 v7 L/ Y2 Z# d5 l问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?; |  b, a5 O& |. G  \& V* F  a; a
* E, K' Q, ^8 s1 g2 p, O- K/ G
答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
+ [4 n! S9 c% B2 ?$ h+ C
3 n" O& `9 t& h1 c) X& O7 t例如:module_init(first_drv_init);  //用于修饰入口函数( J: J1 D7 i* a- I

6 k9 W& u  ?" H% Z6 L( s自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。0 T  r+ r6 e, C7 o/ A
: a, H- y& ?; s9 U
例如:module_exit(first_drv_exit);  //用于修饰出口函数. y) R/ w+ e# G3 ], ~, T# i

% B+ e- ^9 a9 j% {( ?- Q( x1 X9 H# W% `4 p

: p' t. v& D! j0 Y$ J9 I! u驱动源程序如下:
( ]5 d  r, E% E
  @( Q* e% {) Z8 K; }! `, z3 |+ P1 E9 J5 p" n: p0 k
#include <linux/kernel.h>5 z( i" T" w3 q8 ?. ~0 x
#include <linux/fs.h>
9 \  Z# c- v1 J3 j2 J) r4 w7 z#include <linux/init.h>* J" T" h, y6 U% o
#include <linux/delay.h>
, c( a9 u7 [* O( Z, e4 n$ b! q& s#include <asm/uaccess.h>8 l4 o) I2 c% V, \+ X
#include <asm/irq.h>
2 Y1 w- d+ ~0 k* {, j) Q( U. f#include <asm/io.h>
! q( T3 x3 ~2 ^& |#include <linux/module.h>9 {( z6 y" Y7 m
5 t( {7 z6 `- @3 G
$ `7 ?& V0 j% s4 Q
int major;
; {. ~" M7 E- F/ l+ G! cstatic int first_drv_open(struct inode * inode, struct file * filp)
& U& O. q/ B- R/ I3 G' l6 M1 ]{
5 u# W- O/ k/ K4 F        printk("first_drv_open\n");9 L7 a' x% h' V# p, d
        return 0;+ r% a) W2 }' R
}/ @5 U# ^, k/ Y
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)5 @( n1 ]' ~9 j- W  y2 b$ w
{
6 q  z5 ~- d# S9 L' {$ s8 x        printk("first_drv_write\n");
  X+ f/ z9 c4 k- Y. S        return 0;
1 A! v! z  }- M2 p# p2 d}
& d4 F+ s. v/ ]: K2 c, O2 C  D% c! g" d/ j- \8 Y
/* File operations struct for character device */
! g7 n4 A& L- e; e, m) Z* Hstatic const struct file_operations first_drv_fops = {; Z" }5 K( ~2 H+ t" ~
        .owner                = THIS_MODULE,+ S; W0 g5 w5 f+ D
        .open                = first_drv_open,; t5 {, q9 L% G( o0 {4 W; K5 B" _, @
        .write      = first_drv_write,% E# e$ l% u( D
};
: L# b3 p' N- Y& E; d; Y) \* W5 p3 |/ l  a: U' J) v
/* 驱动入口函数 */
8 @# V- f2 }7 Ostatic int first_drv_init(void)& [# Z) \% R8 ~3 a5 ^7 j& t
{) f. E' U" }  `4 M
        /* 主设备号设置为0表示由系统自动分配主设备号 */
" X  P2 }- r' d0 B, V        major = register_chrdev(0, "first_drv", &first_drv_fops);% X7 b1 d3 ]" l5 W$ g
        return 0;
. ]9 g0 E3 C) W, Z) e. ~}
3 @! w5 m6 G; Z
: [! F6 f$ j4 m% y) B/* 驱动出口函数 */
* ]2 m& a) t  ~6 Gstatic void first_drv_exit(void)
8 r0 ^. T1 t' m! k; {. L{
7 x  d) S( K. X5 \, [+ T9 v7 c        unregister_chrdev(major, "first_drv");- l1 f( Q* S( M1 N5 h
}" r! Z6 d  g* [* z

7 U9 Y. q0 k8 a4 w* b: j& Cmodule_init(first_drv_init);  //用于修饰入口函数" j* \: y8 h! E' b
module_exit(first_drv_exit);  //用于修饰出口函数       
' \0 T) \( Z2 A2 p+ `5 I$ V" |" b8 l/ A$ L0 H3 G: h1 l
MODULE_AUTHOR("LWJ");
( h9 h. ^; t/ l4 s2 vMODULE_DESCRIPTION("Just for Demon");* d7 _, q3 M' A
MODULE_LICENSE("GPL");  //遵循GPL协议
  @3 L7 L6 c$ Q9 d. x% \$ P# F& w2 \5 V9 q7 r% a# }, h
Makefile源码如下:) E6 r$ m) L! I0 X* {1 y& S4 O
* M* M) `/ t9 Q( `, r
ifneq ($(KERNELRELEASE),)2 `( y" \  `1 n

4 o. B2 h6 V9 w! Y. D& sobj-m := first_drv.o
) A# A- v/ _1 N. M: w/ g) G* R) k' h1 D" l8 R8 S
else) G% s, s/ q# F; \: Z
        ( X) k  o' `# H
KDIR := /home/opt/EmbedSky/linux-2.6.30.4( P$ m3 o$ D+ t" g" @
1 J! N: y  `* Z, C9 ^' P3 [
all:1 r2 C1 J$ S/ v) ?' L' k# T, c3 O
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
5 K# P1 o* M$ G2 Y  q; e: ?6 rclean:) B0 k5 ?' z- Z# |3 S* l
        rm -f *.ko *.o *.mod.o *.mod.c *.symvers/ d1 Q3 K! I/ ]; E6 g
" A6 B/ q) Z5 B8 {- y) Y% H
endif
! C- I; E# O3 K8 ~7 a2 H6 e9 I! P( P
测试程序如下:) k& G) F3 ^' c/ A4 m; ~$ m$ @
  g  J. s5 ^# x( V, P
#include <stdio.h>7 F) A8 a/ S% D9 \" q. k) r, X, Q$ ]3 i
#include <sys/types.h>
- W: A, _! f. [/ L3 o; ]9 B, G9 c#include <sys/stat.h>6 o1 A$ e2 `% E/ ?6 u0 n, _/ Y; T
#include <fcntl.h>. o* l+ W5 f/ E8 h) D, E
#include <unistd.h>, U+ o2 C; y( f6 t# R3 l5 y

8 {) w% h0 Z' Y; T6 M' a8 u, dint main(void)& R# {3 J" ]2 Y$ t: p1 y; [  I
. d6 R( M! {0 }# ?/ _
{- o. z; |1 J; p1 J4 K0 }" o3 ]( r
        int fd;7 J8 W* d2 N% ~' P
        int val = 1;
$ ]+ n: g/ g. Q9 z1 ~( o6 U+ @        fd = open("/dev/xxx",O_RDWR);
9 d; e8 |$ `+ Y        if(fd < 0)* J+ q8 K  h8 k9 v( l. _6 m, p  H3 g
        {
8 ]6 R0 F% Z0 B2 U- k' D$ L5 I                printf("open error\n");
' l: n9 N: J* @4 ^8 l8 B        }
3 {6 m# W0 r/ A2 S  [       
, B, y" l3 n* q        write(fd,&val,4);' X% I1 ^" C9 M  }8 Y- I: U7 O
        : U# q& C$ }* r  `
        return 0;# g7 Q, n8 M6 @" M. |( n7 Y2 x. r
}4 j1 C( }. j+ n9 }+ d

, W4 s: f- l2 ?. g+ R; K开发板上的测试步骤如下:3 e4 Y( s- e% f# S' @
: Z# Y, s: r0 ]7 f# J$ N: F7 M9 W
[WJ2440]# insmod first_drv.ko 5 U  u. h% C- G2 i
[WJ2440]# ./first_test " I* t! Q# B& D/ \- w: K
open error  o5 L: z# b  s8 p2 p
[WJ2440]# cat proc/devices
" t. M  T9 u& I5 T# p7 {Character devices:2 w! r4 G4 M! C2 M5 ]/ X
  1 mem$ I) t7 ?; _4 r5 ]0 F$ \) ^- I. H
  4 /dev/vc/01 M" F, G, |+ I9 Z/ J; t8 c5 l
  4 tty9 P+ J/ X7 Q1 y4 W: {
  5 /dev/tty
# {2 Q3 P& H! l& i; P, L/ O) g5 T  5 /dev/console
( W3 J7 ^5 ~4 z! s$ `4 m  5 /dev/ptmx
. G- @2 }+ a4 u8 @3 }, I  7 vcs5 u4 y) G2 \' U7 X/ i
10 misc6 R4 F9 i, D% v, _/ B( @7 l/ D+ E
13 input7 |, Q8 l) k' x
14 sound
1 M' I: J4 Q, l# {( |8 r 29 fb
' R3 J, O% p% h8 A5 ^ 81 video4linux& O4 l4 d- E: }8 c
89 i2c
$ s4 k2 j8 o0 u; W2 t 90 mtd0 K( [) \5 c% W9 T
116 alsa
  X) v) ]0 f; R  F! |! Q6 o) D3 {128 ptm# u# J0 c5 q2 F4 F8 h4 Q9 J
136 pts
: H% x! G5 ?, O180 usb
% e$ ^0 E, J  A: M/ h188 ttyUSB2 b5 O6 f5 |7 J7 \% f1 V$ W
189 usb_device
4 G. A8 d) Q+ U! b5 C" q. o5 n204 tq2440_serial
9 n1 k: |2 d+ F" M9 n252 first_drv
/ Z# l0 q" m0 w) u9 V3 ]! F253 usb_endpoint
5 ?+ T( |' ]6 c254 rtc
. a: g; [" L. a
' g6 R/ K1 ]  L' {5 A+ {8 Q7 RBlock devices:
' s6 M, b1 J. m9 q" h259 blkext4 N3 ]+ d: K8 X
  7 loop# E/ I' s. L  A
  8 sd) ^5 O# Y/ I" V: [  U( i. I) s
31 mtdblock
0 s2 |0 k: w" b3 [) o8 r 65 sd" K( U# L) N4 ~7 A
66 sd+ F' r1 w4 ^# k: b9 X
67 sd
( g4 V. F, X' [* I4 q- H 68 sd
% O0 k: r( r/ l 69 sd) M) s6 B- t$ u3 A
70 sd& Q) U$ l/ y' z
71 sd' e: [& ~; J# k4 @9 V2 `* a
128 sd' X2 E3 b+ ?1 W
129 sd' e0 r" h5 C. Q: T/ ]2 q+ V  Q0 S
130 sd
2 |) t+ [6 N6 t# ]- Q; S131 sd. B7 Z. |; x% T
132 sd
: a8 f$ ~0 n7 \' T( C$ I133 sd) H/ y9 C- X- Z) t
134 sd
2 |, @; a) U% h& s2 i! s# G4 B135 sd
$ n) J1 _  _( d8 d' m$ ~179 mmc2 }! i5 Q/ q  @# G; g
[WJ2440]# mknod /dev/xxx c 252 0
) h+ p5 N  J6 ^8 Q/ l( g[WJ2440]# ls -l /dev/xxx 1 R4 @2 c3 h" p5 a4 c' `/ q
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
. z- \2 i' _- }8 D0 j[WJ2440]# ./first_test ; X% z+ v. H( Z6 m
first_drv_open
2 {% f! q: E$ }) ?2 q8 Pfirst_drv_write
( z$ z3 l; s9 d  h: ^3 Z5 f% W, X[WJ2440]#
2 R" Y1 ^1 z/ Q: m: P0 ^3 s
8 o! q, }1 W; H2 W5 L9 |; t$ C$ f5 i, `" J

5 v( f; k. F' h) G/ w

该用户从未签到

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-7-1 13:19 , Processed in 0.078125 second(s), 23 queries , Gzip On.

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

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

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