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

初见linux字符驱动

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
学习驱动也有长达一年多的时间了,受益最深的就是看韦东山老师的视频,如今已经几乎将二期三期的视频全部看完,甚至已经将二期视频看过好几遍,为了再次加深印象,我将韦老师的源码自己全部编写一遍。将所有遇到的问题,记录在此。觉得看了韦老师的视频,再看其他视频都是弱爆了。由于是文章记录,不可能写的非常详细,只摘录关键点,想具体详细的深入,还请去看韦老大的视频吧。
- n1 f. i$ q/ g# Q
) g* b! N8 b7 K2 W这篇文章是主要是讲解字符驱动的框架,并没有涉及高级字符驱动。
5 E1 ?, s* v% e) Q' [. w) S
$ ^9 ]# ?7 [$ Z' t( n, I一、字符驱动框架  X1 r6 P0 r# b# M! l+ x5 W# u

1 l. _4 H( |) ^3 Z! Z8 m$ y------------------------------------------------------------------------
! U: d" Q" |9 s9 i' j1 h6 c- C3 C2 o) T
APP:     open               read                   write
# _! H9 P% ?2 h9 G
! E1 v1 j  ^8 H1 ?( @------------------------------------------------------------------------
% D# g! z" b+ _' D( u
% @: _8 M3 P  N; F' d! q1 r) UC 库
% K7 F+ X- R# i$ n% A" _" g
9 s! g; q" H! A0 Q+ y) H7 X------------------------------------------------------------------------; j0 x) y8 [0 Q5 Z1 H
' F% [1 a% k4 F5 Z
      system_open    system_read       system_write
& M1 l4 g, U. I% s9 }/ k
4 c, D# {; \! r  m; p* w% j$ D. X" h% R0 y9 M% {1 A+ V0 t+ ~

0 `2 x# Q0 }: F7 D( d) s------------------------------------------------------------------------
0 ]' q, p& l( F! b" p# ?" ]+ I3 ~( e, j5 J* M6 @
KERNEL:
' T( r* G8 e, [3 _# \/ k4 {+ C7 L! Z+ P, X9 q
      led_open           led_read               led_wirte$ S8 S. \3 M3 |( ^0 y2 H1 d
9 d! r; k4 j! Z1 ~" o# ^
------------------------------------------------------------------------' n6 s, a5 M+ S/ y
$ d4 |) b. Z, M% u! \+ m

" x1 P  h9 [4 C% Y
; o5 n* j; n3 L问:应用程序open如何找到驱动程序的open函数& K/ @3 ?7 {- u7 f
  e" z- j- R9 \  _+ O; ?
答:应用程序的open通过C库的open函数,通过系统调用的system_open函数,进而通过swi val指令,进入内核,通过一定的办法来找到驱动程序的open函数。
# @5 v& I7 R! i9 p3 q1 }" H/ G7 N+ n0 o
问:通过什么样的方法来找到驱动程序的open函数
) T+ G2 R! i. e+ Q# P/ }
: Y2 F: p7 j$ X$ ?/ a答:通过一个注册函数+设备节点/ d8 ?1 c$ [" a  q: l* h& b/ O7 b! s
; z6 ~& w% q  I8 w- i% ~) v
注册函数如下(旧的注册函数,新的以后再说):
& V: }9 T7 e5 N; R& i8 J# }; ~% i' a) H
register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)( k  z7 D: _7 [! V- A

0 g( S9 N: O% B% Z4 [参数1:主设备号(重要)3 R' L( v6 Z  o7 T
: i7 M8 i! w# W
参数2:名字(不重要)
! C6 l/ u9 e9 C3 v- k8 ~. g# N/ c: U1 G4 A% A: y
参数3:file_operations结构体(重要): A& ~/ }; ]9 w

  ?( Z$ ]& h3 v  h& {7 |设备节点:
/ c+ c4 p( T% N$ t# b5 M: u5 p
. v6 @! ~( t+ m/ F3 ~9 G可以手工创建也可以自动创建,这里暂且只说手工创建
' t, Q" Z( W# c1 q9 F# r/ y5 ?  z' B4 N5 `- a( U
mknod  /dev/xxx  c  252  0, C/ f( _  s, e9 C/ o

3 `: L  E# M$ ?8 E具体什么含义,我就不多说了,看视频吧,很简单。
1 |+ K$ J2 t' m: M4 w, X9 f: j, b. d# J, x. j

) @( I- Y1 E0 W3 x& j& a
  _: N4 U4 [0 Q( K0 f2 B0 f问:应用程序一般是由main函数开始执行,那么驱动程序一般是先执行什么?
: I+ P+ H$ l* E$ p. C7 \1 D! r" O* u: x
答:通过一个宏,指定驱动程序的入口函数,当装载驱动时就会执行入口函数。% k  w  G2 P! {3 ^7 U
: i  k( j/ Q0 d- b$ ~& M$ r- ^
例如:module_init(first_drv_init);  //用于修饰入口函数* q2 W& U# U6 O5 r7 h# o

2 H7 d/ k5 A( H/ b自然地,驱动程序的出口函数,则是在卸载驱动时就会执行出口函数。3 D0 @6 i  _4 m  m) [, P' z
% P$ ?) M/ _5 H2 \( K# Z5 l
例如:module_exit(first_drv_exit);  //用于修饰出口函数5 }- h" f2 T. a9 _5 g& g/ U

) A4 }- R% k+ D0 \7 v( I- F
8 G0 w6 A( J$ s9 o# a$ J3 ~
- v- K  Q: [9 }3 Z; q, `  e驱动源程序如下:
4 ?' N/ c" s% e% k: Y8 w" I0 L5 @* T8 h0 ]" u- f
: E' A2 p* R' Z, y" Y0 j
#include <linux/kernel.h>$ s* p$ w$ I% p  h8 j# s/ C, V
#include <linux/fs.h>
3 c  i: J3 U- @! S( b#include <linux/init.h>' N8 ~- x! a: S* J, w! K+ n6 D' O
#include <linux/delay.h>3 W- X8 w, @! i0 \1 n0 Z% X
#include <asm/uaccess.h>
' @: k( L2 V5 W: }! _) w#include <asm/irq.h>
! g6 _$ t  f5 ^& N# e) ?" p' F& c' g% N#include <asm/io.h>
0 Q5 x$ g) m! A! D#include <linux/module.h>( d% s5 f0 s# j3 o# l1 ?4 N

! w1 n% _. X2 ~/ i0 N% f6 h# j" n5 W2 c" t0 [3 Z) b! ^
int major;# F  @/ w3 S; c6 U3 P* |
static int first_drv_open(struct inode * inode, struct file * filp)
7 c: n$ k" X& R0 z7 z: p0 w. m5 W: M{' U/ O' q/ |0 j' ?1 X
        printk("first_drv_open\n");4 r# w  t8 n5 [
        return 0;& ?( Q2 M; z5 r. [
}
. J2 Z0 ^* \& r# x9 l% Q. w# o" jstatic int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
' t) l7 h4 j5 q6 }{: l% x: Q9 p7 A; Q! w2 k( d
        printk("first_drv_write\n");
* H( ?1 H6 g+ |* ]' @        return 0;
7 z7 q; C1 g7 E& N/ W6 r}( J6 m5 o# z; T  e0 h6 d* v

# c3 y" z0 i2 ~( r/* File operations struct for character device */6 k! E, L% ?7 `5 t0 X
static const struct file_operations first_drv_fops = {
: L0 g& c: K" S* e* c3 v6 H7 ?* L        .owner                = THIS_MODULE,
  X. X1 b5 Y: y! e# |( L" p1 [        .open                = first_drv_open,% [+ ~- m2 p5 g: O
        .write      = first_drv_write,
  d" G0 }4 K( S& {" B. V: t6 g};" e5 z0 P# f5 Z0 l
- C& W  H+ z# o- e
/* 驱动入口函数 */
% {! h2 Q) g% W* ?static int first_drv_init(void)/ }6 {8 G, h0 B; c
{8 }3 \0 K6 @! \, q& K" i
        /* 主设备号设置为0表示由系统自动分配主设备号 */
) ]% ~0 U. {1 {6 \4 ?4 z        major = register_chrdev(0, "first_drv", &first_drv_fops);* s0 ^+ \. F3 H1 L1 m% ~
        return 0;
# b' [( P- K0 d1 K. [}* }) Q) e+ Y& L
- Q; y8 B. N# D# w- o( ]
/* 驱动出口函数 */: P3 ~" m# ?. F' q3 `
static void first_drv_exit(void)6 \- N, X: y- n, w" Y
{9 G2 B" F8 y7 v
        unregister_chrdev(major, "first_drv");2 N. B; }, A+ q4 E
}
# K) x, B  p1 g1 b! n- e: A" m, m; X( Y# S( _3 e
module_init(first_drv_init);  //用于修饰入口函数
2 n) D7 V" S. B8 }. z/ U' amodule_exit(first_drv_exit);  //用于修饰出口函数        ; a/ I4 \1 S0 t; l1 r* p: e2 Y2 n
- @4 Q# e" V6 k3 c: Z% f
MODULE_AUTHOR("LWJ");1 P2 A; V: @. J' b
MODULE_DESCRIPTION("Just for Demon");
' B2 b9 Z3 `1 q' ~: c  ?5 U& |MODULE_LICENSE("GPL");  //遵循GPL协议
8 B! X& D' z( n& ^3 Z; E- ~1 q) F. p% K# i7 {
Makefile源码如下:+ N0 _/ N* @7 R& s4 B  k% L$ v# i

4 y! @& r0 n) V9 }; Difneq ($(KERNELRELEASE),)
- D0 N2 q7 {% D/ A
( S" R, O! V) }; ^" x$ Zobj-m := first_drv.o  Q# D9 R. G& Z( _; ]0 F# U

1 m7 i% p) I! s( w1 Yelse3 D0 S  a& h% b4 M9 w$ t$ e5 t" ^
        & h# v' Z2 u9 t
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
8 X6 `  E) I$ Z# }( f2 \9 E
( }* f+ u" }( f( ball:! h/ D; }2 }  A! {) T2 o
        make -C $(KDIR) M=$(PWD) modules ARCH=ARM CROSS_COMPILE=arm-linux-
" A3 w8 Z& R' S4 l  ]3 Mclean:
: ]* ~0 ?" x( [4 D5 n( P        rm -f *.ko *.o *.mod.o *.mod.c *.symvers5 R4 {3 g) w& |. ?4 T$ s! z/ a9 b0 b! N

, r8 [; {6 k) P( zendif
, p4 v$ N; L  q0 G* x$ O3 H, k
+ D* \% U" R# D: k" ~4 H& ]/ {测试程序如下:
6 {2 S$ I# u3 C: F& V0 l4 P: ?) D: q. s& `' j$ @
#include <stdio.h>
6 \; d$ U9 A7 u+ M8 y3 B#include <sys/types.h>
  O& V4 x4 F- C) b5 C#include <sys/stat.h># D4 n: ?/ u, Y2 R5 }: N8 f
#include <fcntl.h>. L6 A; s" B8 g. g! |% x
#include <unistd.h>0 t1 `' t3 B) d, V" C$ d

. Q+ A% {0 I; k9 @4 \; T# Tint main(void)0 C: p, y% X6 [( P
/ _- J% h7 c7 ~/ e4 C  v
{5 N$ Z- D( i: V6 j
        int fd;
7 U4 J6 \! {$ Y' n) v6 x; N3 u        int val = 1;
1 d) x, }: _1 _; a7 R        fd = open("/dev/xxx",O_RDWR);- v0 F4 Y5 i! ?
        if(fd < 0)' h1 \" N$ o4 q3 j; k. u7 ]7 R6 G, j/ ~9 Z
        {
8 v. h' S0 i2 A" _' o                printf("open error\n");
0 ~, w! z9 v( ?! O        }6 i, }) B% o9 x) l+ E
       
. j) K+ I- a5 D9 h+ w        write(fd,&val,4);9 f' v5 i' i3 U) d, o6 z
       
& T1 B" `0 C: U; s* Y& G# M  |* e: N. ^        return 0;
* e! D- m, [$ V) ?}
* H$ a/ A8 w, f% f1 x: ~& P
& Z0 D5 `3 [+ ]: m$ X* ~/ \" @" K  D. K开发板上的测试步骤如下:+ W6 E+ ^" m- t5 o5 G1 o2 X
, V( F( p9 B) L0 d& r& i1 h
[WJ2440]# insmod first_drv.ko # ^) Z1 ^1 p0 t% G! B- O' I( A; w
[WJ2440]# ./first_test
" m4 n& Q9 w- p9 Mopen error
: p$ [& j$ f  d* r+ |[WJ2440]# cat proc/devices
' B4 F" y8 a; WCharacter devices:
$ p, V9 I# R. f  1 mem. g  r, A; ^& Y( ?2 j7 |% _  q& d
  4 /dev/vc/06 v! R" y( ~$ |: F8 h& l
  4 tty
& }( u7 B* \9 @- J( U+ S! X  5 /dev/tty
5 }& N6 `; D" i0 o: i& t9 ]  5 /dev/console
: i1 Q5 e# \2 c4 v! t% k7 a  5 /dev/ptmx
; ~/ s; ?" V( y( [  7 vcs: d2 M: D; a( t% z5 v2 o. B  l9 ]- m
10 misc
/ x' o$ E. k- p& W9 q- c 13 input0 C1 E) A) ~0 C# ]
14 sound
) S4 j5 V; q: P( | 29 fb9 @1 ]1 m$ [  L& j2 j# J! ]) c
81 video4linux
& q) y  Z& A: f/ X7 Z( S* B 89 i2c' W+ A! {  R; R+ V& M( Q
90 mtd
% F9 Y+ I+ t* R* w, U! L7 Y! e) P116 alsa
( A$ \* c5 p8 M/ b; Z4 g128 ptm1 Q/ g, v2 }5 S/ J/ R3 i5 ~( V3 R
136 pts( `/ |4 i8 e3 ^' s1 i+ D3 Q
180 usb
3 v0 S% C! G. U4 n' A( E5 ^6 F, X3 M188 ttyUSB
, m% O. G5 H% M: O( O189 usb_device8 y* d( m3 m/ _* R; x5 F
204 tq2440_serial2 h3 U5 j" |6 ?; ^8 M5 c( p+ n
252 first_drv
1 h( V% d! [! v+ [3 f253 usb_endpoint
6 h' Q& |( X! Z, S) p5 l254 rtc2 X$ T' v' N. }# l1 |
: t: q2 b8 V% @, x1 O6 o
Block devices:! |1 |; Y3 m3 I- ~
259 blkext
8 b* I. u; r0 l/ e* V  7 loop$ H4 g" s; ^3 C: ^; e5 R% E
  8 sd& U0 v0 n7 S  I. P
31 mtdblock
' z# E2 D1 ~& ]# D! H 65 sd
3 g/ i7 h; \& n3 M1 F& ?9 I/ N 66 sd
; h( ?2 l1 t3 k* U' r6 Y" T! Z) p 67 sd! {  K+ Z; X; Y# l' B2 {0 T" C
68 sd* z' [( g6 P7 i) W  N
69 sd
; D& o/ X0 G* g; ]( _" l 70 sd
4 o( h: g- Z9 W* n& r! `+ k7 P 71 sd
; K5 ]0 O; ~- r, B128 sd* \9 j/ e; n" Z! b  K7 A' |
129 sd9 Y2 _. B0 H7 j$ H, n7 D8 h
130 sd  ~4 d- \7 y( N2 d
131 sd
( a1 D7 W8 K9 X5 Y  M% _5 h6 m132 sd
  l% M( ?+ o. M, r# }3 D( e5 N& y0 u133 sd
; w. z5 V0 ?1 \+ n" q" Y134 sd
; J7 N. W1 ^% X/ f; }135 sd$ Q* c3 c+ y7 c- F# N, ]
179 mmc$ O/ j+ y& ?5 B  Q. \$ I
[WJ2440]# mknod /dev/xxx c 252 00 p1 J/ N& @% }1 g
[WJ2440]# ls -l /dev/xxx 6 E, Q2 ]6 d  P3 m. q( H, k! h
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx6 r* K& p0 d& b1 D
[WJ2440]# ./first_test 5 _4 N5 x4 j* n: F
first_drv_open
/ Z3 w! l) A6 Cfirst_drv_write
+ G- X* p( b+ Y8 H$ i% Q[WJ2440]# " o3 O: s! F' H+ s6 E  y# r  G6 }5 @

, x3 \( v+ w, P5 Y; [- P
& {, w" Q5 W6 c1 |% T: s( \1 b4 g& h8 o8 c! v( A

3 O: F3 t; H" N* ]- R0 f3 r0 |

该用户从未签到

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

该用户从未签到

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

本版积分规则

关闭

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

EDA365公众号

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

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

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

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

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