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

Linux字符设备驱动模版

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
本文将给出Linux字符设备驱动模版。大家可以根据实际需求修改本模版。
) o3 a% e- V# O7 ~
" S  w$ v( `$ K2 z# w驱动名为hello,内部提供一个简单的buffer,用户可以调用write向设备写入数据,并调用read从设备读出数据。/ P0 d1 K, Y1 q, ~. Z3 L
请注意:1. 若连续调用N次write,buffer只会保留最后一次write的数据。
. {. `' k( y3 w             2. 每次read都将清空buffer。因此,必须先写write设备,再read设备。
$ h4 |$ W' d9 U8 M6 I                 3. 目前驱动只能有一个进程访问,允许多个线程访问,并且多个线程共享一个buffer。! q2 C$ Y+ V; q. l. w+ S" q

  L- J% [2 |/ ~4 Z1 J4 w下面的驱动代码适用于内核版本2.6.32,未在其他内核版本上经过测试。
( H( r( z( Y4 B; E9 W9 h2 ^0 n#include
6 w! D4 p: }/ \8 N& j#include
4 T1 M( j, S* p) Y( `* x7 Q#include
; @8 M. _9 d0 q, ^+ a& b, K#include * i' p- \! \2 r0 Q1 E! n
#include
5 c$ T9 r6 ~4 C; o, }2 \#define DEBUG+ C. d; B; x# q! p* k4 q
#include 0 g9 W1 z$ I2 V( ]- e6 h
#include
+ m* C7 _2 x0 o# o2 @0 ~; ~#include
9 m" L# ~+ B& i; V2 R: p#include  # U* u: F, m0 l- c. F. y
#include & ?# a" k& U. b) [

+ K8 |4 b7 \# M& E$ i#define DEVICE_NAME "hello"
3 L- j3 J7 c. Z; V
1 U* ^+ G; \2 a. hstatic unsigned bufsize = 512;! H3 i4 w' d0 K( J: P- U
module_param(bufsize, uint, S_IRUGO);
3 g- e0 J$ I2 N. P- ]* hMODULE_PARM_DESC(bufsize, "data bytes in biggest supported hello buffer");$ K, c3 A! R: e* v6 x
1 f0 S) |! R5 r! n0 q: `
struct hello_data{
' G5 [" u  w% f! {- C  J4 o6 b        char *name;
) V7 c- i2 }3 t        struct cdev chrdev;
8 V& a1 u3 Y0 _# I7 K        struct class *cls;0 i% e+ V6 e1 P- C
        dev_t devt;/ ^# c/ a) M0 N, h1 H- q- ~
        struct device *dev;
7 N3 \; h+ M$ @% C: I- R5 g8 Q, I9 i( \8 i% i0 w! B/ l
        atomic_t available;
* l' l& J% z+ p+ R; T% w8 x+ T: w        struct mutex mlock;  /* Protect @buf */  N! }3 E2 C- g9 u/ n  ]& v/ f
        char *buf;1 A: ?0 u* Q" B/ l% f, [
        size_t bufsize;
% R) D( s# X. w; G+ R6 \        size_t actual_len;
# }$ G# z& ^7 O" F# J5 G};' J" G7 _# G; C* @% p) ^2 S* |

/ I- R$ I/ T1 ]( c/ N2 K" bstatic struct hello_data * hello;& |9 }1 }8 @0 R4 L6 F) g* `
3 R) {9 F* s9 K
static int hello_open(struct inode *inode, struct file *file)( W+ H- d/ t+ x! J# l" X/ i1 R1 |% _
{
: J* J* Z+ Y: @; l( r" ~        struct hello_data *hello = container_of(inode->i_cdev, struct hello_data, chrdev);
' a+ O- l1 l  I3 _/ L; F: Z0 B6 x% g- J
        /* Only ONE user can open the device. */+ a$ r" d4 G* V! d; v
        if(!atomic_dec_and_test(&hello->available)){
. R; l$ n( \; ]' Y                atomic_inc(&hello->available);
0 b/ Y# I: m" D# c                return -EBUSY;
$ T" [: g$ O" h" f        }% x5 c5 j* G/ z+ r

0 E6 ]% m# l* [        dev_dbg(hello->dev, "Hello open\n");
- w3 g* [# T' ~, ]5 n: q# j6 |  Q7 N- ]
        if(!strcmp(hello->name, DEVICE_NAME))
$ Q% B; i+ T! Y& L0 K9 k% v                dev_dbg(hello->dev, "This is hello\n");
) _9 @* B, y  W+ H  b1 E  [& ^: O( E1 [+ A
        file->private_data = hello;# L; g4 x/ o- \# ?3 [2 h

% F+ L8 s& F+ p9 ~; S/ j        return nonseekable_open(inode, file);        
0 Z' z% q5 V( ^( Y' w}
- ?) j- l  O4 V3 G2 T" L* ^
/ r* I! w  [0 p1 H" U9 Xstatic int hello_close(struct inode *inode, struct file *file)$ {* d8 r' u+ k9 U, v3 N
{7 p0 f+ ]5 i9 i1 g
        struct hello_data *hello = file->private_data;
0 w4 s+ c% E, Z) Z$ q: P0 Z+ I' ]% G2 Q/ u- w) Y2 d' L
        dev_dbg(hello->dev, "Hello close\n");$ F# A( g5 o/ l8 I$ h
       
  {  t3 O6 D. I" ]; y$ R& L9 [        file->private_data = NULL;, l  w7 c: E, k( P. A$ f
        atomic_inc(&hello->available);4 }# `0 e, m/ {2 ^6 p
& P+ h+ D4 [2 x$ l! l- ~; {0 Z
        return 0;
, L; |# Z/ X) ~. g, I}
1 T% k) g9 V) g2 g. |
( ^) A' N4 C$ b; I1 \* n, mstatic int  hello_read(struct file *file, char __user *buf, size_t count, loff_t *offp)
( A" i& G* ^7 h% e2 `0 Y{7 J* W# {. F$ G0 H* ~0 ?+ _
        struct hello_data *hello = file->private_data;
5 E2 u$ H; f2 @4 _# a3 j        unsigned long ret;% P& h- k" @% T7 b+ L8 ~
        u64 len;
. B0 W- B7 Q4 O: q
/ n/ Y' h: ^% D- v        if(hello->actual_len == 0 || count > hello->actual_len)9 O4 j4 l, ^' |0 Y! F+ ]
                return -EINVAL;6 p6 m$ Y, Q% P0 F* q

+ [" U4 i; m. u( B  W+ F% S6 ?        len = min(count, hello->actual_len);/ O9 K1 Z. `$ m# D( q3 q% b: Z& G7 C: R
        mutex_lock(&hello->mlock);! s. u) P. j2 h, h' f' o
        ret = copy_to_user(buf, (void *)hello->buf, len);5 }: Y- `9 @: A/ M
        if(ret < 0){  a) |$ |; L& K; @
                ret = -EFAULT;
  n: Y; h$ G3 J/ I: V* ]                goto out;) e& {# a6 y8 e6 R
        }8 {( n# p' E0 A, N! J' K: f, W/ a+ F

4 b4 X' f5 ^) b/ y        hello->actual_len = 0;5 t" W1 e9 c9 }0 f0 x, V) ~
        ret = len;
( T3 U# L  D3 X+ ^% _4 P9 t4 K* d
, ^9 I% J( M0 @) I+ [4 z6 {8 p" eout:* R/ C+ y5 J1 B- @+ ^! r0 s
        mutex_unlock(&hello->mlock);
  e1 f4 `) r5 i. D        return ret;! i/ V( X" c+ q  g4 `! Z# W
}2 G% n: S9 C, q1 v3 {0 F3 h5 S
! k$ A' D1 U6 Z' P$ g
static int  hello_write(struct file *file, const char __user *buf, size_t count, loff_t *offp)/ A; V/ @3 v  _' d7 N! u
{
3 m: r1 R/ I& K; b+ e5 _        struct hello_data *hello = file->private_data;' z7 _  z# Q) S: ~  }
        unsigned long ret;
! g4 Q( q6 H& o6 @- x        u64 len;; J* X: O% j+ ^# ?2 E. z5 W- l1 _
3 Q) }$ _% j9 \" i0 C! i5 [# d1 w
        if(count > hello->bufsize)
; f' x3 N4 g' _  \! D7 Z4 t. w                return -EINVAL;/ D. w3 u/ k% U% z# d

+ V# h# v0 T, U8 q        len = min(hello->bufsize, count);
' q/ o6 ]7 h, D6 `  m
. a9 j. @3 W/ V! I( N( b* E        mutex_lock(&hello->mlock);
! i5 U4 Q$ c) J2 G1 @1 }& a        ret = copy_from_user(hello->buf, buf, len);- I3 U( f- M& h
        if(ret < 0){2 A8 k+ e6 }2 e/ ?6 r! @8 k/ [
                ret = -EFAULT;
0 X7 B  G$ x; K$ V                goto out;% e0 ]$ u& Q) Q1 w& X
        }, K; x9 c9 O0 k+ K& s( q

5 s, K% n0 Q( D+ h        hello->actual_len = len;
- V4 V/ p) H! Z; ]: D2 C6 I        ret = len;" r' _/ e. ?, D  ]; `
out:- y# t( a, U1 h- v# i
        mutex_unlock(&hello->mlock);8 ^3 Y( P) [% t+ v( k
        return ret;5 @5 k7 ^6 M+ v4 n! |" `+ V
}9 Q, g/ v. e+ T0 Z" V
* R0 m+ f. ~) s; F" c
static struct file_operations hello_fops =2 L0 }- F7 X% D
{0 h5 m4 p6 q& R, f! t
        .owner        = THIS_MODULE,
& R  t, S- L; [) o6 T        .open   = hello_open,) G: n2 \, y) a1 @; w
        .release= hello_close,- Z' {3 Q: _, j  ]; H
        .read         = hello_read,
+ t& k' K8 F6 g4 K* R/ [        .write         = hello_write,
4 E! F) M7 K3 L/ \        .llseek = no_llseek,
* M; f. ^- C: E+ q. \' o2 T4 `};* C# `3 p/ U+ o- ], E1 i
2 `4 I! ]' x; A$ W- k
static int __init hello_init(void)
& m* C. ^/ v5 B$ U{% D9 G4 U: V' @' l" A
        int ret;
) D) o6 n  H# a+ a
- U5 _4 M, V$ ?/ T6 k        hello = kmalloc(sizeof(struct hello_data), GFP_KERNEL);/ @: Y- x8 |, \3 S* k
        if(hello == NULL){
0 x$ E6 V  O) B% u9 b                printk(KERN_ERR "Unable to malloc struct hello_data\n");3 R$ X7 W2 s& x; J% Z. O% ?
                return -ENOMEM;
- @# K# o. _- h% R        }5 e5 G2 r# y: o
        / h; l0 w: c; ]4 z  {# g
        hello->name = DEVICE_NAME;
. ^( L* D: s: Y3 \, n        mutex_init(&hello->mlock);
- d: e6 f3 R: B- t6 W        atomic_set(&hello->available, 1);6 A5 n+ f$ q" [7 q' b

: ?1 q8 R- l2 y; g: O' N( L        hello->buf = kmalloc(bufsize, GFP_KERNEL);
, f- S2 Z& @& G" v4 l+ H- }        if(hello->buf == NULL){
. F' l1 x  C8 B" K, w1 ?: I' G1 V                printk(KERN_ERR "Unable to malloc buf\n");
7 i' b1 l8 X( _$ i                ret = -ENOMEM;
# J) S2 I. w  O                goto err_no_mem;
( X9 I- Y' i- F" ^        }
! \# Y) s# }+ l2 q+ L7 E3 `        hello->bufsize = bufsize;
/ e; G# [( o- G& r, W        printk(KERN_DEBUG "Buffer size: %d \n", hello->bufsize);
2 {8 z. \3 }) f  x6 h2 F+ m0 Z+ y/ a6 H0 [
        /* Alloc the device number dynamically which is stored in the first parameter */- u: R& V- m1 U
            ret = alloc_chrdev_region(&hello->devt, 0, 1, DEVICE_NAME);; S- q( @# i- k$ v+ c2 ~& ~9 A
        if(ret < 0){: Z+ ]0 q, E' z: C" W$ T7 L% z
                printk("Alloc chrdev region error\n");
2 i4 g/ f, R( _3 t' Z6 D                goto error_alloc_region;
4 F, J4 D- m# H; N; |        }
( h8 X* |, D8 u% ?        printk(KERN_DEBUG "Major = %d, minor = %d\n", MAJOR(hello->devt), MINOR(hello->devt));4 c# t1 q; G2 W6 q, T8 m( p

$ y! @2 ?1 n  I8 ]( v# d        cdev_init(&hello->chrdev, &hello_fops);( ?3 G4 ]' _  @5 F
        hello->chrdev.owner = THIS_MODULE;' O' ^8 @3 ]& H# z, J
        hello->chrdev.ops = &hello_fops;
# o: x  H8 \- g" U( H# [3 C1 K, Q6 y7 m0 v
        ret = cdev_add(&hello->chrdev, hello->devt, 1);# k# x8 o9 g6 V0 c1 L& L- C( N
        if(ret < 0){
" N2 S2 _% |2 B2 z( m+ b                printk(KERN_ERR "Cdev add error\n");% Z0 U" Y/ p" Q' z
                goto error_cdev_add;
) P+ W" A) O! _! f7 s        }$ V8 ?& }9 d. g& m6 J6 Z4 j
8 x# S: {5 o! E' Z/ l8 K& I
        hello->cls = class_create(THIS_MODULE, DEVICE_NAME);3 s/ B' w2 v2 {" G, o
        if(IS_ERR(hello->cls)){' X) K, B5 \1 |% @
                printk(KERN_ERR "Class create error\n");4 d# P( p0 X! Q& q" m# q
                ret = -1;
' X7 A* E4 j; [% Z. l% p8 P+ L7 }: z3 Y                goto error_class_create;& o# [. z2 `7 H3 w
        }
7 B+ Y$ ^* w. x9 S& w" l0 k: r# o
5 z8 v' t) k8 x' Y" Z( M, `) u% F        hello->dev = device_create(hello->cls, NULL, hello->devt, NULL, DEVICE_NAME);( z5 Z2 S9 v$ |9 Y5 ]* l: l: O5 ^
        if(IS_ERR(hello->dev)){, q& [9 g4 v$ p5 N* w$ H; n' p* S- G
                printk(KERN_ERR "Create device error\n");
4 t" l6 H8 M9 q8 B, b! I                ret = -1;
+ x0 F- E- l* l8 ~                goto error_device_create;5 t% I/ b6 N% K: {* l
        }% G7 U/ i# `( m+ Y  |: r
# R+ q0 L8 h) Q" ^/ o# ^
        return 0;
( k1 U0 Z1 F3 l* [4 _, t1 ?+ F, o- b- z6 C. j+ C
error_device_create:
7 Q% l5 M$ L) J& Z9 Eerror_class_create:! u, N8 I, |. ]- c. ?
        cdev_del(&hello->chrdev);
$ _3 O' t( N9 S
; w6 l: o( D: |2 e$ A2 n3 \6 r4 C$ ierror_cdev_add:; f# i; K* g& }& G1 d
        unregister_chrdev_region(hello->devt, 1);
. N  ]' X& d7 d5 t6 ]# x; `* X. j; y  a9 X! `/ b( ]+ P
error_alloc_region:  ^# k! _; O  ], R" d4 P, h- A
        kfree(hello->buf);! w6 D0 z  W9 E" c# R6 D

& S3 f8 B* a$ i7 m; d# s, f$ w# herr_no_mem:  N2 V# @7 z9 g" g$ J5 P" L  j' g- E
        kfree(hello);" ?+ ]; p$ k& L9 x3 U- J  v& i
) `; Z0 w& x, Y: C& h# d8 k# Q
        return ret;; `# \0 `0 B4 X+ W
}
: Y! f3 T) g( i6 ?3 Y) O# Y
: f: E) k. {. T& J, E8 y, s" cstatic void __exit hello_exit(void)6 ]$ S( s7 H; P' X) B
{
8 U4 X' k& g' f        dev_dbg(hello->dev, "Hello world exits\n");
$ @) c; g6 {7 D+ A/ g5 x5 Y  k, }$ f& w5 s! k$ L4 a
        cdev_del(&hello->chrdev);3 x+ x4 I* ^* O4 h- j
        unregister_chrdev_region(hello->devt, 1);        ) C+ B$ E5 W- ?+ R0 y- Q
        device_destroy(hello->cls, hello->devt);
- U; D* J  ]. @        class_destroy(hello->cls);7 _- c6 D% h, b+ l7 }
        kfree(hello->buf);
, h& M1 I# P( |6 E3 g- w        kfree(hello);
' h3 m" p5 r8 C  }} # J2 z- B8 g9 g' C7 t( W

( r0 a  O6 S% S) m6 y) ~$ b/ Mmodule_init(hello_init);6 r& k9 o7 o8 g/ _% w7 i0 {2 J
module_exit(hello_exit);8 e2 G2 C1 f8 }. `

5 ?% C9 d  D2 mMODULE_LICENSE("GPL");
2 t2 L7 r2 E; OMODULE_AUTHOR("yj4231@hotmail.com");4 h7 u/ o' V, ]
MODULE_DESCRIPTION("Hello template driver");  H6 ~% _2 w  f* A1 F/ s( O
5 y0 ]. Y# Q+ y3 c3 [: J- G
1 A: T( m2 ~" M( B7 j; m; Z
对应的测试程序如下:- u4 j2 O* q8 i% ^  Z& F
#include
5 H3 o' b2 p! O  h7 r: A. A#include
' i! M1 u3 ]& L#include
- N" ^" p: X9 K* m#include
7 b# a  X0 I- W7 o( J# @. b6 y#include
. E; ~, V# S) D! H/ q0 _7 T( C#include . v9 e+ J& I3 j4 v* K7 p! C
#include 5 k2 X2 T, |9 J/ F. L
% y; ]: h& d" S- w0 U2 w4 P& i7 z
int main(int argc, char **argv)! ^* M0 E9 Y# i0 |  _: w4 L- P
{3 A8 h1 `4 ~* f0 p9 Z4 y
        int fd, ret;
0 J5 w3 N: i8 w( V: }        char data[512+1] = "Hello test";3 {# Z7 @# b1 F3 \) A
        char buf[512+1];
7 S& B+ a( I. V        int n;" d6 P* M7 b- ]- C& i; P( g* D

( }4 a6 d7 Q3 r4 U        fd = open("/dev/hello", O_RDWR);! e& y/ {5 A6 d0 {8 j% K* t" ~
        if(fd < 0){
2 ]0 p9 x- @- D5 a  j  g) i3 U- s                perror("Open device fail");: `7 q& \! Q) Q
                return -1;
, _( ?5 r- ]/ m, s3 S% u7 g        }; v0 P% O  a; R; k
, Q- i  l, L- I
        n = strlen(data);
" J  w9 q& u+ D$ l        ret = write(fd, data, n);
! b- J5 j* p# k7 R$ z/ x5 L: }        if(ret != n){2 I' n7 v1 a* G" u
                printf("Write failed\n");
5 p% B) e1 i8 _$ N  \1 S- f                exit(-1);
8 @; [& x$ K# T0 A2 Q' N4 n        }8 Y5 k% R& R( V
        printf("Write retval: %d\n", ret);* C$ e+ l0 n( U5 ~& k; d5 {# }
3 a! c; ]8 ~( I# Z- t0 ^* B8 z
        ret = read(fd, buf, n);: t3 c5 b) E) E& m0 t. X
        if(ret != n){& ^8 {; B2 ~2 F4 D4 q  @
                printf("Read failed\n");
/ ~  [# }8 `6 @6 I                exit(-1);
3 ~' ]+ v+ b- H4 s5 r        }
% A) H/ Y- q+ \+ o% v- @( t        buf[n] = '\0';( ~1 k- \7 E3 R; D

3 H) K* r  I) b0 a. U* X        printf("Read retval %d, %s\n", ret, buf);
) x: Q) T7 A1 A2 H2 ~        sleep(1);
. D' a& O3 H/ \1 n        close(fd);2 w' R' C0 v/ i% n8 Y, j5 i
}
( z, H2 a, k( A% S8 X+ m% {- ?3 @* f/ S% U9 o* ^* i
+ c9 y7 c9 j/ Y" A9 g

, Q% g( {/ W! M" L# R. ZHistory:- V8 d% E6 C: n/ S; c- h4 d) K: R. D
2014.02.15  单进程,多线程共享buffer版本(2.6.32)。7 a$ a0 _& B' `# _3 O$ b  v
# u$ c/ C" g- }; d! R
8 S6 W2 g9 M! W- V& Y% k

  u/ q) c8 m! I7 }3 P4 _; w0 t

该用户从未签到

2#
发表于 2020-5-29 11:02 | 只看该作者
Linux字符设备驱动模版
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

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

EDA365公众号

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

GMT+8, 2025-11-26 00:33 , Processed in 0.156250 second(s), 24 queries , Gzip On.

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

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

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