guowenxue
2024-12-23 b8e5f60912c77d52214c21e67fa91ec5f522c54c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
 * Copyright (C) 2024 LingYun IoT System Studio
 * Author: Guo Wenxue <guowenxue@gmail.com>
 *
 * A character skeleton driver example in linux kernel.
 */
 
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>   /* printk() */
#include <linux/fs.h>       /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/cdev.h>     /* cdev */
#include <linux/version.h>  /* kernel version code */
#include <linux/moduleparam.h>
 
//#define CONFIG_DYNAMIC_ALLOC
 
/* device name and major number */
#define DEV_NAME         "chrdev"
 
#ifdef CONFIG_DYNAMIC_ALLOC
#define DEV_MAJOR  0
#else
#define DEV_MAJOR  79
#endif
 
int dev_major = DEV_MAJOR;
module_param(dev_major, int, S_IRUGO);
 
#ifdef CONFIG_DYNAMIC_ALLOC
struct cdev   *cdev;
#else
struct cdev    cdev;
#endif
 
static int chrdev_open (struct inode *inode, struct file *file)
{
    return 0;
}
 
static int chrdev_close (struct inode *node, struct file *file)
{
    return 0;
}
 
static struct file_operations chrdev_fops = {
    .owner          = THIS_MODULE,
    .open           = chrdev_open,  /* open()  implementation */
    .release        = chrdev_close, /* close() implementation */
};
 
static int __init chrdev_init(void)
{
    dev_t      devno;
    int        rv;
 
    /* 1. Allocate device number */
    if(0 != dev_major)
    {
        devno = MKDEV(dev_major, 0);
        rv = register_chrdev_region(devno, 1, DEV_NAME);
    }
    else
    {
        rv = alloc_chrdev_region(&devno, 0, 1, DEV_NAME);
        dev_major = MAJOR(devno);
    }
 
    if(rv < 0)
    {
        printk(KERN_ERR "%s driver can't use major %d\n", DEV_NAME, dev_major);
        return -ENODEV;
    }
 
    /* 2. Allocate and initialize cdev */
#ifdef CONFIG_DYNAMIC_ALLOC
    cdev = cdev_alloc();
    if( !cdev )
    {
         printk(KERN_ERR "Unable to allocate cdev\n");
         goto failed1;
    }
    cdev_init(cdev, &chrdev_fops);
#else
    cdev_init(&cdev, &chrdev_fops);
    cdev.owner = THIS_MODULE;
#endif
 
    /* 3. Register cdev to linux kernel */
#ifdef CONFIG_DYNAMIC_ALLOC
    rv = cdev_add(cdev, devno, 1);
#else
    rv = cdev_add(&cdev, devno, 1);
#endif
    if( rv )
    {
        rv = -ENODEV;
        printk(KERN_ERR "%s driver regist failed, rv=%d\n", DEV_NAME, rv);
        goto failed1;
    }
 
    printk(KERN_INFO "%s driver on major[%d] installed.\n", DEV_NAME, dev_major);
    return 0;
 
failed1:
    unregister_chrdev_region(devno, 1);
 
    printk(KERN_ERR "%s driver installed failed.\n", DEV_NAME);
    return rv;
}
 
static void __exit chrdev_exit(void)
{
#ifdef CONFIG_DYNAMIC_ALLOC
    cdev_del(cdev);
#else
    cdev_del(&cdev);
#endif
    unregister_chrdev_region(MKDEV(dev_major,0), 1);
 
    printk(KERN_INFO "%s driver removed!\n", DEV_NAME);
    return;
}
 
module_init(chrdev_init);
module_exit(chrdev_exit);
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>");