linux驱动开发之pwm蜂鸣器
2016-11-23 15:01
399 查看
http://blog.csdn.net/changliang7731/article/details/52297561
驱动开发,控制pwm蜂鸣器!
蜂鸣器有多种类型,一种是给电就叫,另一种给电了还不行,还需要freq才会叫。大概称作有源和无源吧!
我们此时将buzzer的驱动加入到内核中去。
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
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
蜂鸣器的操作:可以打开,让它叫,亦或者不叫,响的时候可以改变它的频率。即蜂鸣器发出声响的尖锐程度不同。
duty的改变在这里无太大作用。蜂鸣器的工作电压是一个恒定值,一般为5v或者3.v。改变duty的结果无非和 开关的结果一样,叫或者不叫而已,所以函数没有实现这一部分!
将此文件关联编译到内核,重新编译内核。make uImage
编译成功。
使用uboot加载新内核,内核打印出 request pwm 0 for pwm-buzzer failed。
同时,在busybox勾线的nfs根文件目录的dev目录下未自动生成 pwm-buzzer设备文件。
这里问题出现了。
程序在调用pwm_request 请求一个pwm设备时返回失败。
pwm_request的声明在 include/linux/pwm.h中
2
3
4
5
1
2
3
4
5
这里可以看出它是返回一个 pwm_device 结构体指针的函数,成功则返回请求的pwm_device的结构体指针,在这里发现需要
把CONFIG_PWM 或者CONFIG_HAVE_PWM打开才可以,否则会调用else下面的:
2
3
4
5
1
2
3
4
5
这里我们先重新配置内核,把CONFIG_PWM或者CONFIG_HAVE_PWM给选上。再编译内核
再装载内核,最后还是报错在申请pwm device失败那边!
这边有点不懂了。
不过有在网上和书上有看过别人的文章和思路。因为pwm需要用到pwm定时器用于方波的产生,所以在此之前我们试着把pwm0对应的定时器初始化一下,试试看会不会有惊喜。
在arch/arm/mach-s5pv210/mach-smdkv210.c中,加一行:
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
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
此时,再重新编译内核,加载内核到ram中,内核打印出pwm-buzzer initialized
然后在busybox构建的根文件系统的dev目录下可以找到pwm-buzzer 设备文件,这里,我们的实验算是成功了一大半了!
写测试程序。我们已经生成buzzer设备文件,并将对应的驱动绑定到此设备上!当我们打开此设备,并对此设备文件进行操作时便会调用到我们写的驱动。
测试程序:
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
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
编译档案生成可执行程序后,放在文件系统的根目录下,运行。
按+可以增加pwm的频率,按-可以减小pwm的频率。esc按键关掉蜂鸣器。
这样基本上pwm蜂鸣器的驱动已经开发完成!
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
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
Misc设备是一个主设备号为10的字符设备。
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
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
与蜂鸣器比较类似的应该是panel 背光设备了!背光一般固定频率,duty可变,手机上的背光一般就是控制背光pwm的duty来实现亮度的变化!
顶0
踩
驱动开发,控制pwm蜂鸣器!
蜂鸣器有多种类型,一种是给电就叫,另一种给电了还不行,还需要freq才会叫。大概称作有源和无源吧!
我们此时将buzzer的驱动加入到内核中去。
/* * linux/drivers/char/smart210_pwm.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> #include <linux/fb.h> #include <linux/backlight.h> #include <linux/err.h> #include <linux/pwm.h> #include <linux/slab.h> #include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/gpio.h> #include <mach/gpio.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #define DEVICE_NAME "pwm-buzzer" #define PWM_IOCTL_STOP 0 #define PWM_IOCTL_SET_FREQ 1 #define PWM_IOCTL_SET_DUTY 2 #define NS_IN_1HZ (1000000000UL) #define BUZZER_PWM_ID 0 #define BUZZER_PMW_GPIO S5PV210_GPD0(0) static struct pwm_device *pwm0buzzer; static struct semaphore lock; static void pwm_set_freq(unsigned long freq) { int period_ns = NS_IN_1HZ / freq; pwm_config(pwm0buzzer, period_ns / 2, period_ns); pwm_enable(pwm0buzzer); s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_SFN(2)); } static void pwm_stop(void) { s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT); pwm_config(pwm0buzzer, 0, NS_IN_1HZ / 100); pwm_disable(pwm0buzzer); } static int smart210_pwm_open(struct inode *inode, struct file *file) { if (!down_trylock(&lock)) return 0; else return -EBUSY; } static int smart210_pwm_close(struct inode *inode, struct file *file) { up(&lock); return 0; } static long smart210_pwm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { switch (cmd) { case PWM_IOCTL_SET_FREQ: if (arg == 0) return -EINVAL; pwm_set_freq(arg); break; case PWM_IOCTL_STOP: case PWM_IOCTL_SET_DUTY: default: pwm_stop(); break; } return 0; } static struct file_operations smart210_pwm_ops = { .owner = THIS_MODULE, .open = smart210_pwm_open, .release = smart210_pwm_close, .unlocked_ioctl = smart210_pwm_ioctl, }; static struct miscdevice smart210_misc_dev = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &smart210_pwm_ops, }; static int __init smart210_pwm_dev_init(void) { int ret; ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME); if (ret) { printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO); return ret; } gpio_set_value(BUZZER_PMW_GPIO, 0); s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT); pwm0buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME); if (IS_ERR(pwm0buzzer)) { printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME); return -ENODEV; } pwm_stop(); sema_init(&lock, 1); ret = misc_register(&smart210_misc_dev); printk(DEVICE_NAME "\tinitialized\n"); return ret; } static void __exit smart210_pwm_dev_exit(void) { pwm_stop(); misc_deregister(&smart210_misc_dev); gpio_free(BUZZER_PMW_GPIO); } module_init(smart210_pwm_dev_init); module_exit(smart210_pwm_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("FriendlyARM Inc."); MODULE_DESCRIPTION("S5PV210 PWM Driver");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
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
蜂鸣器的操作:可以打开,让它叫,亦或者不叫,响的时候可以改变它的频率。即蜂鸣器发出声响的尖锐程度不同。
duty的改变在这里无太大作用。蜂鸣器的工作电压是一个恒定值,一般为5v或者3.v。改变duty的结果无非和 开关的结果一样,叫或者不叫而已,所以函数没有实现这一部分!
将此文件关联编译到内核,重新编译内核。make uImage
编译成功。
使用uboot加载新内核,内核打印出 request pwm 0 for pwm-buzzer failed。
同时,在busybox勾线的nfs根文件目录的dev目录下未自动生成 pwm-buzzer设备文件。
这里问题出现了。
程序在调用pwm_request 请求一个pwm设备时返回失败。
pwm_request的声明在 include/linux/pwm.h中
#if IS_ENABLED(CONFIG_PWM) || IS_ENABLED(CONFIG_HAVE_PWM) /* * pwm_request - request a PWM device */ struct pwm_device *pwm_request(int pwm_id, const char *label);1
2
3
4
5
1
2
3
4
5
这里可以看出它是返回一个 pwm_device 结构体指针的函数,成功则返回请求的pwm_device的结构体指针,在这里发现需要
把CONFIG_PWM 或者CONFIG_HAVE_PWM打开才可以,否则会调用else下面的:
#else static inline struct pwm_device *pwm_request(int pwm_id, const char *label) { return ERR_PTR(-ENODEV); }1
2
3
4
5
1
2
3
4
5
这里我们先重新配置内核,把CONFIG_PWM或者CONFIG_HAVE_PWM给选上。再编译内核
再装载内核,最后还是报错在申请pwm device失败那边!
这边有点不懂了。
不过有在网上和书上有看过别人的文章和思路。因为pwm需要用到pwm定时器用于方波的产生,所以在此之前我们试着把pwm0对应的定时器初始化一下,试试看会不会有惊喜。
在arch/arm/mach-s5pv210/mach-smdkv210.c中,加一行:
static struct platform_device *smdkv210_devices[] __initdata = { &s3c_device_adc, &s3c_device_cfcon, &s3c_device_fb, &s3c_device_hsmmc0, &s3c_device_hsmmc1, &s3c_device_hsmmc2, &s3c_device_hsmmc3, &s3c_device_i2c0, &s3c_device_i2c1, &s3c_device_i2c2, &s3c_device_rtc, &s3c_device_ts, &s3c_device_usb_hsotg, &s3c_device_wdt, &s3c_device_timer[0],// for pwm buzzer &s5p_device_fimc0, &s5p_device_fimc1, &s5p_device_fimc2, &s5p_device_fimc_md, &s5p_device_jpeg, &s5p_device_mfc, &s5p_device_mfc_l, &s5p_device_mfc_r, &s5pv210_device_ac97, &s5pv210_device_iis0, &s5pv210_device_spdif, &samsung_asoc_idma, &samsung_device_keypad, &smdkv210_dm9000, &smdkv210_lcd_lte480wv, };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
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
此时,再重新编译内核,加载内核到ram中,内核打印出pwm-buzzer initialized
然后在busybox构建的根文件系统的dev目录下可以找到pwm-buzzer 设备文件,这里,我们的实验算是成功了一大半了!
写测试程序。我们已经生成buzzer设备文件,并将对应的驱动绑定到此设备上!当我们打开此设备,并对此设备文件进行操作时便会调用到我们写的驱动。
测试程序:
#include <stdio.h> #include <termios.h> #include <unistd.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define PWM_IOCTL_SET_FREQ 1 #define PWM_IOCTL_STOP 0 #define ESC_KEY 0x1b static int getch(void) { struct termios oldt,newt; int ch; if (!isatty(STDIN_FILENO)) { fprintf(stderr, "this problem should be run at a terminal\n"); exit(1); } // save terminal setting if(tcgetattr(STDIN_FILENO, &oldt) < 0) { perror("save the terminal setting"); exit(1); } // set terminal as need newt = oldt; newt.c_lflag &= ~( ICANON | ECHO ); if(tcsetattr(STDIN_FILENO,TCSANOW, &newt) < 0) { perror("set terminal"); exit(1); } ch = getchar(); // restore termial setting if(tcsetattr(STDIN_FILENO,TCSANOW,&oldt) < 0) { perror("restore the termial setting"); exit(1); } return ch; } static int fd = -1; static void close_buzzer(void); static void open_buzzer(void) { fd = open("/dev/pwm-buzzer", 0); if (fd < 0) { perror("open pwm_buzzer device"); exit(1); } // any function exit call will stop the buzzer atexit(close_buzzer); } static void close_buzzer(void) { if (fd >= 0) { ioctl(fd, PWM_IOCTL_STOP); //if (ioctl(fd, 2) < 0) { // perror("ioctl 2:"); //} close(fd); fd = -1; } } static void set_buzzer_freq(int freq) { // this IOCTL command is the key to set frequency int ret = ioctl(fd, PWM_IOCTL_SET_FREQ, freq); if(ret < 0) { perror("set the frequency of the buzzer"); exit(1); } } static void stop_buzzer(void) { int ret = ioctl(fd, PWM_IOCTL_STOP); if(ret < 0) { perror("stop the buzzer"); exit(1); } printf( "Pwm buzzer stop\n"); } int main(int argc, char **argv) { int freq = 1000 ; open_buzzer(); printf( "\nBUZZER TEST ( PWM Control )\n" ); printf( "Press +/- to increase/reduce the frequency of the BUZZER\n" ) ; printf( "Press 'ESC' key to Exit this program\n\n" ); while( 1 ) { int key; set_buzzer_freq(freq); printf( "\tFreq = %d\n", freq ); key = getch(); switch(key) { case '+': if( freq < 20000 ) freq += 10; break; case '-': if( freq > 11 ) freq -= 10 ; break; case ESC_KEY: case EOF: stop_buzzer(); exit(0); default: break; } } }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
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
编译档案生成可执行程序后,放在文件系统的根目录下,运行。
按+可以增加pwm的频率,按-可以减小pwm的频率。esc按键关掉蜂鸣器。
这样基本上pwm蜂鸣器的驱动已经开发完成!
一些note:
struct miscdevice { int minor;//次设备号,misc混杂设备公用一个主设备号,当.minor=MISC_DYNAMIC_MINOR,表示动态分配次设备号 const char *name;//名称,驱动作者自己定义 const struct file_operations *fops;//文件操作接口,一般具体驱动在这里实现 struct list_head list; struct device *parent; struct device *this_device; const char *nodename; umode_t mode; }; //misc device主要填充前3个内容,后面的不懂,以后有用到再研究! struct file_operations { struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, loff_t, loff_t, int datasync); int (*aio_fsync) (struct kiocb *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); int (*check_flags)(int); int (*flock) (struct file *, int, struct file_lock *); ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); int (*show_fdinfo)(struct seq_file *m, struct file *f); }; //这里我们仅仅初始化了file_operations里面的几个函式 static struct file_operations smart210_pwm_ops = { .owner = THIS_MODULE, .open = smart210_pwm_open, .release = smart210_pwm_close, .unlocked_ioctl = smart210_pwm_ioctl, }; static int smart210_pwm_open(struct inode *inode, struct file *file); static int smart210_pwm_close(struct inode *inode, struct file *file); static long smart210_pwm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) //我们可以看到这三个函式必须严格按照file_operations的内部对应的函数指针的参数来构造 //其实真正的驱动是写在smart210_pwm_ioctl中,这里实现pwm的频率和duty: static void pwm_set_freq(unsigned long freq) { int period_ns = NS_IN_1HZ / freq; pwm_config(pwm0buzzer, period_ns / 2, period_ns); pwm_enable(pwm0buzzer);//pwm0使能 s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_SFN(2));//pwm接口配置成pwm } int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns); //这里很明确,period_ns填充代表pwm的频率。duty_ns的填充代表duty,也就是占空比!这里的buzzer默认占空比是50% //函数里面的实现暂时不去研究它是如何实现的 //最后我们来确认两个主要函数 static void __exit smart210_pwm_dev_exit(void) { pwm_stop(); misc_deregister(&smart210_misc_dev);//注销misc设备 gpio_free(BUZZER_PMW_GPIO); } static int __init smart210_pwm_dev_init(void) { int ret; ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME); if (ret) { printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO); return ret; } gpio_set_value(BUZZER_PMW_GPIO, 0); s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT); pwm0buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME); if (IS_ERR(pwm0buzzer)) { printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME); return -ENODEV; } pwm_stop(); sema_init(&lock, 1); ret = misc_register(&smart210_misc_dev); printk(DEVICE_NAME "\tinitialized\n"); return ret; } //这个也比较好理解,你把buzzer当做一个混杂设备,用混杂设备来声明,来实现它的驱动,那么同样,注册、注销设备时便需要把它当做 //misc设备来处理,这也是这里为什么会有misc_deregister,misc_register的原因.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
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
Misc设备是一个主设备号为10的字符设备。
static int __init misc_init(void) { int err; #ifdef CONFIG_PROC_FS proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc");//注册一个misc类 err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) goto fail_remove; err = -EIO; if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))//向内核注册主设备号为10的字符设备 goto fail_printk; misc_class->devnode = misc_devnode; return 0; fail_printk: printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: remove_proc_entry("misc", NULL); return err; } int misc_register(struct miscdevice * misc) { dev_t dev; int err = 0; INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); if (misc->minor == MISC_DYNAMIC_MINOR) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i >= DYNAMIC_MINORS) { mutex_unlock(&misc_mtx); return -EBUSY; } misc->minor = DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); } else { struct miscdevice *c; list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { mutex_unlock(&misc_mtx); return -EBUSY; } } } dev = MKDEV(MISC_MAJOR, misc->minor);//生成设备主次号 misc->this_device = device_create(misc_class, misc->parent, dev, misc, "%s", misc->name);//自动创建设备节点使用 if (IS_ERR(misc->this_device)) { int i = DYNAMIC_MINORS - misc->minor - 1; if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); err = PTR_ERR(misc->this_device); goto out; } /* * Add it to the front, so that later devices can "override" * earlier defaults */ list_add(&misc->list, &misc_list); out: mutex_unlock(&misc_mtx); return err; }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
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
与蜂鸣器比较类似的应该是panel 背光设备了!背光一般固定频率,duty可变,手机上的背光一般就是控制背光pwm的duty来实现亮度的变化!
顶0
踩
相关文章推荐
- 嵌入式Linux之我行——PWM在ARM Linux中的原理和蜂鸣器驱动实例开发
- linux驱动开发之pwm蜂鸣器
- 嵌入式Linux之我行——PWM在ARM Linux中的原理和蜂鸣器驱动实例开发
- PWM在ARM Linux中的原理和蜂鸣器驱动实例开发
- mini2440 pwm蜂鸣器设备驱动开发源代码(宋宝华框架)
- 基于ARM-contexA9-蜂鸣器pwm驱动开发
- [S5PV210 Linux字符驱动之PWM蜂鸣器驱动
- 基于ARM-contexA9-蜂鸣器pwm驱动开发
- 【引用】Linux-2.6.32.2内核在mini2440上的移植(十七)---移植PWM控制蜂鸣器驱动
- ①tiny4412 Linux驱动开发之蜂鸣器
- Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动
- linux驱动开发之蜂鸣器驱动源码分析(一)
- Linux 字符设备驱动开发基础(二)—— 编写简单 PWM 设备驱动
- 基于S3C2440的Linux-3.6.6移植 PWM蜂鸣器驱动
- [S5PV210 Linux字符驱动之PWM蜂鸣器驱动
- Linux-2.6.32.2内核在mini2440上的移植(十七)---移植PWM控制蜂鸣器驱动 .
- linux-2.6.32在mini2440开发板上移植(18)之移植PWM蜂鸣器驱动
- linux驱动开发之九鼎板载蜂鸣器驱动测试【转】
- s3c2440 linux3.0下PWM使用之蜂鸣器驱动移植
- .Linux-2.6.32.2内核在mini2440上的移植(十七)---移植PWM控制蜂鸣器驱动