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

linux字符驱动之初见

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。
8 M, _. y. i+ `0 `6 n$ ^4 w( z6 L- g. d5 Z
这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。5 F1 }6 [! Q* Y8 ]5 N* f$ T
8 N2 G1 h4 {. e1 ], N( m- N' @
一、字符驱动框架7 ]' \3 ?8 v4 C( ?4 F4 f

: w" G9 W2 X0 f------------------------------------------------------------------------
" Y' U& i# u4 t+ c& Y5 Z" W* ]+ o* A/ {; O
APP:     open               read                   write$ X% `$ u( D) j% {% ]

# K% y8 o! q. |( A( B  x------------------------------------------------------------------------" r: h0 r/ |2 S

. H: }. ?- z  o# jC 库- J- Q8 p: e7 V5 E" l
3 Z6 C8 r; T/ q9 t
------------------------------------------------------------------------/ O, Y, B3 j: |, P: Z4 K
% U  G: i  M- Q
      system_open    system_read       system_write3 U# @/ [$ s; \7 ^& ^8 J  i6 ^
+ |' }# `% ~+ k6 m  [/ T6 n
$ Q& q, B& O6 r3 A) Y
9 k5 J+ I* T& l3 f6 G* |0 U% K5 ~; e
------------------------------------------------------------------------
2 g" x3 ^/ r, N4 q( K; D$ |) S3 @. M  @6 w1 V
KERNEL:
* c0 C# r) u/ d1 `' c
% E. X  L4 g* A% ~  `7 K- x      led_open           led_read               led_wirte, Q% k  i# r  L5 C3 N; ^

  d0 J: l" @; I3 x' C$ ?------------------------------------------------------------------------9 U4 C+ [# S( u1 E& U- y
2 k. i' C3 T- u3 C. y: ?" [4 t
' X1 @4 E9 E& q
% O7 Y) q$ u6 Q3 q" q" ]& ?
问:应用程序open如何找到驱动程序的open函数
9 S: y% ~; B4 _  h9 w/ g9 u4 H8 v% B# [2 ?5 F1 b& h0 v$ s
答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。! }. s& x4 ?$ H
& w% z# O: K% W0 j1 X; b! Q) N# ~% ]
问:通过什么样的方法来找到驱动程序的open函数# [: I0 h8 O- o  n( g8 c

; p" r% d+ N8 R2 O8 \& ^答:通过一个注册函数+设备节点, J$ r: u, `8 A2 {6 z

2 V) V8 _3 i  o$ c3 i0 u+ A; `% i注册函数如下(旧的注册函数,新的以后再说):7 c1 t7 Z0 k) T

, \- O  [$ Y0 c: r4 P3 q7 p7 cregister_chrdev(unsigned int major, const char * name, const struct file_operations * fops)
/ ?: [/ ?) ]3 T5 J
& A2 B5 J0 G" `1 `* I* l参数1:主设备号(重要)7 e2 w" v# r4 a7 Y2 k* `) X

" Y  s$ b9 |2 Q" `, Q: F; b参数2:名字(不重要); s, b: Q% ]0 |+ h) Z" D% U

. d2 |- R9 U" q6 w1 m, I参数3:file_operations结构体(重要)5 j  |/ x! m) Z0 r& t! [
  }9 c" L, b1 \
设备节点:1 [7 ^" B  p# B+ o- t! v
$ ?( r7 }* h% H# M: j
可以手工创建也可以自动创建,这里暂且只说手工创建8 a  K8 T3 g* q" @4 f' l: o
1 B+ d0 r' ?+ B& l# H0 b4 U
mknod  /dev/xxx  c  252  0
6 x$ l+ e- Q7 K, v6 x* z3 m  E( L5 K
$ T2 X( z1 K0 m具体什么含义,我就不多说了,看视频吧,很简单。
  Q" U! v. y6 Q/ z
- O* e7 S2 Y* {9 S* N, U  `
0 |' u3 j6 y( n  w9 n0 Q
) ]8 ^$ H  v2 I9 X  o- N0 w8 A问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?
0 k+ o, {. E9 i: ~; U2 d' p6 Q8 s4 O  m  S
答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。
( r- ?. d" l. ~; h# Z( n. i& f
例如:module_init(first_drv_init);  //用于修饰入口函数7 Z- \9 f1 L- e9 O# u2 y

. j6 x- k5 Q) B$ J3 G3 B) [  w自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。8 q" ^8 |; D7 H  |9 k) Z
) A; l$ M6 e% }% k. J+ f
例如:module_exit(first_drv_exit);  //用于修饰出口函数
+ N3 l. q: k) l. r! m, @6 i- B& {+ R) w2 A

; k; h, k: Z0 M5 ?% H% m& s. i2 d" T4 c. z. e
驱动源程序如下:
. k9 F! A- p7 b% I$ m
! f. C! P5 y  k& b6 n- b, f! N0 f) S9 b: t/ S  O3 N# ]/ B' h
#include <linux/kernel.h>
) u+ q  ]: C! l5 O' Z# f) |#include <linux/fs.h>' U. I. |' l3 V% G8 c; k& B: Y9 c. K
#include <linux/init.h>/ _! g4 N& M5 ^: W3 L' K" _
#include <linux/delay.h>
) j0 A* h$ a- p  a- B$ k; j#include <asm/uaccess.h>. M' G  D. p- Z" G- B- m# Z7 H" I
#include <asm/irq.h>. O# y/ N5 ^0 b+ a. O3 X$ ], Q
#include <asm/io.h>
/ @$ V" |5 H) _2 f+ N#include <linux/module.h>/ e6 n. q) m: o1 K# T# y+ I3 w
7 Q4 y7 `) O; o8 W+ U
& ^; v; L5 `( Q" P
int major;5 Z) m9 z7 z: G* G$ p% x
static int first_drv_open(struct inode * inode, struct file * filp)
3 T, L# G( U* E. D{+ G2 A" K% m# R& u+ h
        printk("first_drv_open\n");/ W/ v$ M+ \! T& S
        return 0;  R! Y7 f: y& D) ]( T
}" ?+ G4 J# B! k) o: W
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos): g3 @: r  e8 ^! \( N" i
{2 x' p& o) X! |* p
        printk("first_drv_write\n");
- U9 Z0 T- Q5 Z( Z; z5 l1 D3 M        return 0;$ k7 L0 I# T& ?. P4 f; T
}' }7 @) s" r) C7 ]; E- g  R

! V6 r% o. _! m! [0 P- J8 k; @/* File operations struct for character device */
; A3 h* k+ g# m8 X* hstatic const struct file_operations first_drv_fops = {4 T/ L9 j: c" Q+ m% \6 W, U
        .owner                = THIS_MODULE,
- J; S( F7 V6 y/ x  v! s        .open                = first_drv_open,7 J9 e6 v% M, \' D3 {* F$ v
        .write      = first_drv_write,
; ]- n0 ^4 h$ W% k; P};: S, h+ `7 \8 h7 N6 i, W1 T; T5 f

( W/ Y+ Z2 Q% j& O5 J/* 驱动入口函数 */
+ J; U! B1 g- fstatic int first_drv_init(void)
+ f, `* f( K  x. _' t{
# p4 k- u* z; M0 r& g6 H, Y        /* 主设备号设置为0表示由系统自动分配主设备号 */0 R' H# X$ Q/ S6 {# \
        major = register_chrdev(0, "first_drv", &first_drv_fops);7 V& T& V  d* X) d
        return 0;( ~/ w: X7 P1 D  B, F- o) L
}
- P+ B: P' w, I3 L( p
# E# f/ W/ l  V/* 驱动出口函数 */
) ]" G3 H3 G' M! o! ^static void first_drv_exit(void)
3 i7 I, S; f9 V" S1 Y% _, {  j{
  |4 O! E+ u0 [* C        unregister_chrdev(major, "first_drv");) J3 D. ^5 i3 m+ @% f4 R
}1 Y! Q" u) R% a

+ s' g- u' }! ~  _$ W/ E3 v, pmodule_init(first_drv_init);  //用于修饰入口函数
+ x2 |' P& t' A- q  F/ R. n( Hmodule_exit(first_drv_exit);  //用于修饰出口函数       
7 ]0 \; @9 p; A* t! o) d$ ?* P( F" t% u% u# _2 m6 Y  o- `
MODULE_AUTHOR("LWJ");
4 t3 L& c. [) p& m# kMODULE_DESCRIPTION("Just for Demon");- y3 @" M: ?% D* i) ?
MODULE_LICENSE("GPL");  //遵循GPL协议
6 u  n4 x: C" J* o
2 ^! u; @% G8 A  g- l8 Z: g. U# p, z, IMakefile源码如下:
9 S1 n  c& Y) r' J# F; i; _" N& o& z& A+ Y  X: i" G8 ~; K
ifneq ($(KERNELRELEASE),)
, Q5 N# o$ c2 k4 `0 v& a! x6 c9 _6 m# o4 c
obj-m := first_drv.o
' t! W# G0 h5 q, l- T3 i; Y8 I
9 |& k3 @' {% S8 R: I1 celse
4 M) j6 M* O$ S  u       
, ?+ k: R# n% J. }KDIR := /home/opt/EmbedSky/linux-2.6.30.4& U5 H# p- {8 i

: l( _9 c5 o$ Q( ?" m2 E$ call:) G7 {8 J9 o: \; T) l0 q1 u6 t7 t
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
$ c8 X% Q% z( S3 M6 }clean:
8 Y2 J- O+ O+ ~9 j: l, Z2 t) G' [        rm -f *.ko *.o *.mod.o *.mod.c *.symvers
$ s  ^# o. u3 N# r4 z8 v. b! x( h" x- U' l4 E8 f4 h
endif
( `, _) v; ^& A2 y& E
  \0 X9 ]' s; s% N$ Y' V测试程序如下:) x1 F6 e6 N" Y
  H3 v. i/ t/ O/ p* r
#include <stdio.h>+ Z" X+ X  `; h
#include <sys/types.h>
/ z" B: Y* l1 P6 A/ w  U9 H#include <sys/stat.h>
' L7 h+ U* B+ q7 y3 z: Y+ h#include <fcntl.h>0 q& a% L" w- h* H7 ]: H5 ~( m
#include <unistd.h>, |+ X& z( \; |: B# C8 X8 @
+ ?2 q' @+ g5 m5 e8 u/ b0 ~5 d' _
int main(void)9 @( I4 G. t- }/ F

( z& e4 L% ?" X  P( v{: R3 S/ @  Z; B8 E
        int fd;
: N2 j; d7 ?) A$ q* l4 j% v' x        int val = 1;& ~0 _' F7 Z  f) n
        fd = open("/dev/xxx",O_RDWR);
& a9 m. w; u; c) B' \        if(fd < 0)
& ~0 l" g* _' t; Y9 A        {
9 x; F3 ^7 s* S# @2 U' r5 e                printf("open error\n");5 x4 W7 n9 {% _
        }
8 W/ t6 c3 E% u" V       
# y+ q1 y3 b. R+ d7 p: `        write(fd,&val,4);
( G3 `' b5 K0 t, \6 g6 }        8 i% O) S- l; e* r6 q
        return 0;  }2 q) b& Z& e
}
3 x* `2 V/ ?- H4 T* y7 _* u& K1 m9 H  ]9 V% W# n
开发板上的测试步骤如下:
' {" I' i6 R8 v, V* n! j) Z6 z* N4 X8 Z9 X8 ]7 S* ]
[WJ2440]# insmod first_drv.ko
7 ?! N" x' p5 i- A7 ?% L3 B, I[WJ2440]# ./first_test ) j3 D6 U+ H, O& Z7 u0 i) N' q
open error7 D9 w/ d: x& M. v$ ^, |/ ]
[WJ2440]# cat proc/devices
! x* p- p7 ?; y4 T, tCharacter devices:4 F' Z1 h6 P0 [. s
  1 mem7 ~- r* _2 m  U
  4 /dev/vc/0- W  X, Z% N1 f" O
  4 tty1 z5 {5 F4 m& j
  5 /dev/tty
& ?( f3 P( ~  B4 q. h4 U  5 /dev/console8 K) r: |+ C5 n# j- s, C
  5 /dev/ptmx
3 v8 y; ^( Z0 [. \  7 vcs& U( L* s/ ^" r
10 misc
* L, v: s  S3 z3 t9 H1 v 13 input. X, }4 R( m( `: T, v2 K. G
14 sound7 \2 s- [9 q" ]( N# L2 N
29 fb7 i" ^+ F& J: }' b' l4 K1 T! F; y
81 video4linux
$ f( b- w9 C/ I. B 89 i2c) E# ]) `% O$ p: S% O9 D7 ?1 {7 o
90 mtd
8 M- F9 F% @" R( e! V  T( k116 alsa1 h7 W3 F. }- L8 D- x
128 ptm
  M, x. ^8 n; i. I* B+ u' B: x136 pts
# X3 x) _, J/ P% H7 k180 usb* G1 Z' Q1 G# c3 K9 O5 N$ p4 Z& |4 P
188 ttyUSB
/ a/ V" W3 M' S" B189 usb_device
8 ^, j6 Q5 O: a* F* G' c4 |204 tq2440_serial
+ Y& s: e7 v2 M& L7 E3 }252 first_drv8 F/ p; b8 f0 d: v9 Z% s. v
253 usb_endpoint' q5 t9 m3 C( ?$ }! E
254 rtc$ W) p* h% r4 r9 P* s% b
* T$ J' Y1 w, S! E& r8 \2 _
Block devices:3 ~( N, A. r4 F! y' V
259 blkext
- o* S+ ?( f* i- r, {  7 loop
: s( h8 }$ M+ n  8 sd
" Y8 q- p+ ]" X$ h5 S: o 31 mtdblock8 j) c! R2 g! H5 z, V
65 sd& D, {7 s; l, ]5 {4 X: @4 s
66 sd, ^& r' y8 y! s! C$ \# }
67 sd& O6 X) R  L3 y
68 sd7 [# o) B: r6 @/ c7 \- T5 j
69 sd5 u) `, {$ j1 i& p/ d5 h# \1 M, a
70 sd; U5 p$ A! r" m! Y9 L3 B" ]% ]' s
71 sd
2 x. k$ Y: Z- u# ]128 sd
4 l- K' Q+ E8 ~* p" U, s129 sd
9 m% i; L  I9 w, C. A  j130 sd* j( T' U  D0 R
131 sd( P# [0 p9 T9 V+ Q( h
132 sd0 J6 @5 E" m1 ]. m* }$ [$ [6 u
133 sd' d, d: ?# ?: E. f8 A; r
134 sd7 t+ t) s$ F1 K
135 sd
! Y0 [* |, k; _179 mmc; }! T; d) Y5 w5 w
[WJ2440]# mknod /dev/xxx c 252 0) c+ u0 u7 E+ d+ i
[WJ2440]# ls -l /dev/xxx . b" H! L  N. Q" F  P
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx9 {( T; p  K' h) O$ C: A1 Y' R
[WJ2440]# ./first_test - I5 z7 y, N% ~9 L! J. X$ U
first_drv_open; e) i) b, ?; R5 z* d, M
first_drv_write% K9 M$ b8 W% p
[WJ2440]# + l' ?$ l% F6 q, B* E4 F! u) ~

4 b* W2 Z# z) l  }7 `5 ^" [8 Z3 n' x2 l+ Q

6 P, l  ~/ `, w: h" y

该用户从未签到

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-11-26 10:08 , Processed in 0.171875 second(s), 23 queries , Gzip On.

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

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

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