抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

misc 的意思是混合、杂项的,因此 MISC 驱动也叫做杂项驱动。

1.内核自带MISC驱动简介

  • 所有的 MISC 设备驱动的主设备号都为 10,不同的设备使用不同的从设备号。

  • MISC 设备会自动创建 cdev,不需要像我们以前那样手动创建,因此采用 MISC 设备驱动可以简化字符设备驱动的编写。

  • 需要向 Linux 注册一个 miscdevice 设备, miscdevice是一个结构体 :

1
2
3
4
5
6
7
8
9
10
11
struct miscdevice  {
int minor;
const char *name;
const struct file_operations *fops;
struct list_head list;
struct device *parent;
struct device *this_device;
const struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
  • 定义一个 MISC 设备(miscdevice 类型)以后我们需要设置 minor、 name 和 fops 这三个成员变量。

  • minor 表示子设备号, MISC 设备的主设备号为 10,这个是固定的,需要用户指定子设备号, Linux 系统已经预定义了一些 MISC 设备的子设备号 。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #define PSMOUSE_MINOR		1
    #define MS_BUSMOUSE_MINOR 2 /* unused */
    #define ATIXL_BUSMOUSE_MINOR 3 /* unused */
    /*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */
    #define ATARIMOUSE_MINOR 5 /* unused */
    #define SUN_MOUSE_MINOR 6 /* unused */
    #define APOLLO_MOUSE_MINOR 7 /* unused */
    ..............
    #define MISC_DYNAMIC_MINOR 255
  • name 就是此 MISC 设备名字,当此设备注册成功以后就会在/dev 目录下生成一个名为 name的设备文件。

  • fops 就是字符设备的操作集合, MISC 设备驱动最终是需要使用用户提供的 fops操作集合。

  • 使用以下函数向内核注册和卸载miscdevice

1
2
extern int misc_register(struct miscdevice *misc);
extern int misc_deregister(struct miscdevice *misc);

如果设置miscdevice里面minor为255的话,表示由内核自动分配次设备号。

2.使用MISC框架

1.设备树:

打开dts文件,在根节点下添加beep节点:

1
2
3
4
5
6
7
beep{
compatible = "zwl,beep";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_beep>;
beep-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
status = "okay";
};

2.头文件包含

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

3.platform框架

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
//probe
static int miscbeep_probe(struct platform_device *dev)
{
return 0;
}
//remove
static int miscbeep_remove(struct platform_device *dev)
{
return 0;
}
//platform匹配表
static const struct of_device_id beep_of_match[] = {
{ .compatible = "zwl,beep" },
{},
};
//platform
static struct platform_driver miscbeep_driver = {
.driver = {
.name = "cbus,beep",
.of_match_table = beep_of_match, //设备树匹配表
},
.probe = miscbeep_probe,
.remove = miscbeep_remove,
};
//入口
static int __init miscbeep_init(void)
{
return platform_driver_register(&miscbeep_driver);
}
static void __exit miscbeep_exit(void)
{
platform_driver_unregister(&miscbeep_driver);
}
module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cbus");

4.MISC框架

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
#define MISCBEEP_NAME "miscbeep"
#define MISCBEEP_MINOR 255

//misc struct
struct miscbeep_dev
{
struct device_node *nd; //设备节点
int beep_gpio;
};
struct miscbeep_dev miscbeep;
static int miscbeep_open(struct inode *inode, struct file *file)
{
file->private_data = &miscbeep;
return 0;
}

static ssize_t miscbeep_write(struct file *file, const char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static int miscbeep_release(struct inode *inode, struct file *file)
{
return 0;
}
//字符设备操作集
struct file_operations miscbeep_fops = {
.owner = THIS_MODULE,
.open = miscbeep_open,
.write = miscbeep_write,
.release = miscbeep_release,
};
struct miscdevice beep_miscdev = {
.minor = MISCBEEP_MINOR,
.name = MISCBEEP_NAME,
.fops = &miscbeep_fops,
};
//probe
static int miscbeep_probe(struct platform_device *dev)
{
int ret = 0;
//初始化IO
miscbeep.nd = dev->dev.of_node;

miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpios", 0);

if (miscbeep.beep_gpio < 0)
{
ret = -EINVAL;
printk("can not find gpio\r\n");
goto fail_findgpio;
}

ret = gpio_request(miscbeep.beep_gpio, "beep");
if (ret)
{
printk("can not request gpio %d\n", miscbeep.beep_gpio);
ret = EINVAL;
goto fail_findgpio;
}

ret = gpio_direction_output(miscbeep.beep_gpio, 1); //输入高电平
if (ret < 0)
{
printk("can not set output\r\n");
goto fail_setoutput;
}

//misc驱动注册
ret = misc_register(&beep_miscdev);
if (ret < 0)
{
printk("misc_register failed\n");
goto fail_setoutput;
}
return 0;
fail_setoutput:
gpio_free(miscbeep.beep_gpio);
fail_findgpio:
return ret;
}
//remove
static int miscbeep_remove(struct platform_device *dev)
{
gpio_set_value(miscbeep.beep_gpio, 1);
gpio_free(miscbeep.beep_gpio); //释放GPIO
misc_deregister(&beep_miscdev); //misc驱动卸载
return 0;
}

加载驱动后,使用命令

1
ls /dev/miscbeep -lk

image-20241208121659952

可以看到主设备号为10,次设备号为57。

3.实验

1.驱动

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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define MISCBEEP_NAME "miscbeep"
#define MISCBEEP_MINOR 144
#define BEEP_OFF 0
#define BEEP_ON 1

//misc struct
struct miscbeep_dev
{
struct device_node *nd; //设备节点
int beep_gpio;

};
struct miscbeep_dev miscbeep;



static int miscbeep_open(struct inode *inode, struct file *file)
{
file->private_data = &miscbeep;
return 0;
}

static ssize_t miscbeep_write(struct file *flie, const char __user *buf, size_t cnt, loff_t *offt)
{
int ret;
unsigned char databuf[1];
struct miscbeep_dev *dev = flie->private_data;

ret = copy_from_user(databuf, buf, cnt);
if (ret < 0)
return -EFAULT;

if (databuf[0] == BEEP_ON)
{
gpio_set_value(dev->beep_gpio, 0);
}
if (databuf[0] == BEEP_OFF)
{
gpio_set_value(dev->beep_gpio, 1);
}

return 0;
}

static int miscbeep_release(struct inode *inode, struct file *file)
{
return 0;
}
//字符设备操作集
struct file_operations miscbeep_fops = {
.owner = THIS_MODULE,
.open = miscbeep_open,
.write = miscbeep_write,
.release = miscbeep_release,
};

struct miscdevice beep_miscdev = {
.minor = MISCBEEP_MINOR,
.name = MISCBEEP_NAME,
.fops = &miscbeep_fops,
};

//probe
static int miscbeep_probe(struct platform_device *dev)
{
int ret = 0;
//初始化IO
miscbeep.nd = dev->dev.of_node;

miscbeep.beep_gpio = of_get_named_gpio(miscbeep.nd, "beep-gpios", 0);

if (miscbeep.beep_gpio < 0)
{
ret = -EINVAL;
printk("can not find gpio\r\n");
goto fail_findgpio;
}

ret = gpio_request(miscbeep.beep_gpio, "beep");
if (ret)
{
printk("can not request gpio %d\n", miscbeep.beep_gpio);
ret = EINVAL;
goto fail_findgpio;
}

ret = gpio_direction_output(miscbeep.beep_gpio, 1); //输入高电平
if (ret < 0)
{
printk("can not set output\r\n");
goto fail_setoutput;
}

//misc驱动注册
ret = misc_register(&beep_miscdev);
if (ret < 0)
{
printk("misc_register failed\n");
goto fail_setoutput;
}

printk("beep probe success\n");
return 0;

fail_setoutput:
gpio_free(miscbeep.beep_gpio);
fail_findgpio:
return ret;
}

//remove
static int miscbeep_remove(struct platform_device *dev)
{
gpio_set_value(miscbeep.beep_gpio, 1);
gpio_free(miscbeep.beep_gpio); //释放GPIO
misc_deregister(&beep_miscdev); //misc驱动卸载
printk("beep remove success\n");
return 0;
}

//platform匹配表
static const struct of_device_id beep_of_match[] = {
{ .compatible = "zwl,beep" },
{},
};

//platform
static struct platform_driver miscbeep_driver = {
.driver = {
.name = "cbus,beep",
.of_match_table = beep_of_match, //设备树匹配表
},
.probe = miscbeep_probe,
.remove = miscbeep_remove,
};

//入口
static int __init miscbeep_init(void)
{
return platform_driver_register(&miscbeep_driver);
}

static void __exit miscbeep_exit(void)
{
platform_driver_unregister(&miscbeep_driver);
}

module_init(miscbeep_init);
module_exit(miscbeep_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cbus");

2.应用

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
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include "poll.h"
#include "sys/select.h"
#include "sys/time.h"
#include "linux/ioctl.h"
#include "signal.h"


/* argc:应用参数个数
* argv[]:具体参数内容,字符串形式

* ./miscbeepAPP /dev/miscbeep 1 关
* ./miscbeepAPP /dev/miscbeep 0 开
*/
int main(int argc, char *argv[])
{
int fd, retvalue;
char *filename;
unsigned char databuf[2];

if(argc != 3){
printf("Error Usage!\r\n");
return -1;
}

filename = argv[1];

/* 打开led驱动 */
fd = open(filename, O_RDWR);
if(fd < 0){
printf("file %s open failed!\r\n", argv[1]);
return -1;
}

databuf[0] = atoi(argv[2]); /*将字符转换为数字*/

retvalue = write(fd, databuf, sizeof(databuf));
if(retvalue < 0){
printf("BEEP Control Failed!\r\n");
close(fd);
return -1;
}

close(fd); /* 关闭文件 */
return 0;
}

3.实验演示

image-20241208125141007

评论