linux驱动初探之杂项设备(控制两个GPIO口)

时间:2021-09-14 23:36:19

关键字:linux驱动、杂项设备、GPIO

  此驱动程序控制了外接的两个二极管,二极管是低电平有效。

上一篇博客中已经介绍了linux驱动程序的编写流程,这篇博客算是前一篇的提高篇,也是下一篇博客(JNI)的底层程序

 

一样的在平台文件中配置设备信息

1 #ifdef CONFIG_HELLO_CTL
2 struct platform_device s3c_device_hello_ctl = {
3 .name = "jni",
4 .id = -1,
5 };
6 #endif

 

1 #ifdef CONFIG_HELLO_CTL
2 &s3c_device_hello_ctl,
3 #endif

 

在编写驱动程序之前要确定需要控制哪个GPIO接口,同时要保证该GPIO口没有被其他程序占用,若被占用则需要取消编译那个驱动程序。

经过查找开发板原理图准备使用CAM_VSYNC和CAM_HREF两个端口

linux驱动初探之杂项设备(控制两个GPIO口)

这两个端口对应于平台文件的EXYNOS4212_GPIO(1)与EXYNOS4212_GPIO(2)两个脚,也就是说只要控制这两个脚,就是控制了硬件上的两个脚。

linux驱动初探之杂项设备(控制两个GPIO口)

使用杂项设备编写驱动会比字符类设备简单,因为杂项设备的主设备号规定了为10,他能够挂255个从设备号。

同样的,从init函数开始:

 1 static void jni_exit(void){
2
3 printk("jni_exit ...\n");
4
5 platform_driver_unregister(&jni_driver);
6
7 }
8
9 static int jni_init(void){
10
11 int err;
12
13 printk("jni_init start...\n");
14
15 err = platform_driver_register(&jni_driver);
16
17 printk("state is %d\n",err);
18
19 return 0;
20 }
21
22 module_init(jni_init);
23 module_exit(jni_exit);

通过platform_driver进行注册,然后申明一个platform_driver结构体,在这里要注意!!这里的.name与我们刚开始时在平台文件中的.name必须要一致,否则会注册失败!也就是说内核会自动进行匹配

 1 struct platform_driver jni_driver = {
2 .probe = jni_probe,
3 .remove = jni_remove,
4 .shutdown = jni_shutdown,
5 .suspend = jni_suspend,
6 .resume = jni_resume,
7 .driver = {
8 .name = "jni",
9 .owner = THIS_MODULE,
10 }
11 };

如果匹配成功,那么会进入驱动的probe函数中,所以一般初始化操作都写在了probe函数中,而不像字符类设备是写在init函数中!

 1 static int jni_probe(struct platform_device *pdv){
2 int ret,i;
3 printk("jni_probe start..\n");
4
5 for(i=0; i<GPIO_NUM; i++)
6 {
7 ret = gpio_request(led_gpios[i], "LED");
8 if (ret < 0) {
9 printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,i, ret);
10 }
11 else{
12 printk("%s: request GPIO %d for LED success, ret = %d\n", DEVICE_NAME,i, ret);
13 s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
14 gpio_set_value(led_gpios[i], 0);
15 //gpio_free(led_gpios[i]);
16 }
17 }
18
19 ret = misc_register(&jni_dev);
20 if(ret<0)
21 {
22 printk("jni:register device failed!\n");
23 goto exit;
24 }
25
26 return 0;
27
28 exit:
29 misc_deregister(&jni_dev);
30 return ret;
31 }
32
33 static int jni_remove(struct platform_device *pdv){
34 //int i;
35 printk("jni_remove...\n");
36
37 misc_deregister(&jni_dev);
38
39
40 return 0;
41 }
42
43 static void jni_shutdown(struct platform_device *pdv){
44
45 return ;
46 }
47
48 static int jni_suspend(struct platform_device *pdv,pm_message_t pmt){
49
50 return 0;
51 }
52
53 static int jni_resume(struct platform_device *pdv){
54
55 return 0;
56 }

在probe函数中会请求gpio口,即gpio_request,如果请求失败,那肯定是某个驱动占用了该gpio口,需要手动取消。

然后设置为输出。最后调用杂项设备注册函数misc_register进行注册。

1 static  struct miscdevice jni_dev = {
2 .minor = MISC_DYNAMIC_MINOR,
3 .name = DEVICE_NAME,
4 .fops = &jni_ops,
5 };

这里终于出现久违的fops函数了,也就是驱动操作函数。

1 static struct file_operations jni_ops = {
2 .owner = THIS_MODULE,
3 .open = jni_open,
4 .release = jni_release,
5 .unlocked_ioctl = jni_ioctl,
6 };

这里的函数接口就是为上层应用提供啦。

 1 static long jni_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
2 int ret;
3 printk("Hello JNI and cmd is %d,arg is %d\n",cmd,arg);
4
5 switch(cmd)
6 {
7 case 0:
8 case 1:
9 if (arg > 2) {
10 return -EINVAL;
11 }
12 gpio_set_value(led_gpios[arg], cmd);
13
14 break;
15
16 default:
17 return -EINVAL;
18 }
19
20 return 0;
21 }
22
23 static int jni_release(struct inode *inode, struct file *file){
24
25 printk("jni release\n");
26
27 return 0;
28 }
29
30
31 static int jni_open(struct inode *inode, struct file *file){
32
33 printk("jni open\n");
34
35
36 return nonseekable_open(inode,file);
37 }

最后附上完整的驱动代码

linux驱动初探之杂项设备(控制两个GPIO口)linux驱动初探之杂项设备(控制两个GPIO口)
  1 #include <linux/init.h>
2 #include <linux/module.h>
3
4 /*驱动注册的头文件,platform结构体和驱动注册与注销*/
5 #include <linux/platform_device.h>
6
7 /*杂项设备头文件*/
8 #include <linux/miscdevice.h>
9
10 /*设备节点头文件*/
11 #include <linux/fs.h>
12
13
14 /*Linux中申请GPIO的头文件*/
15 #include <linux/gpio.h>
16 /*三星平台的GPIO配置函数头文件*/
17 /*三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件*/
18 #include <plat/gpio-cfg.h>
19 #include <mach/gpio.h>
20 /*三星平台4412平台,GPIO宏定义头文件*/
21 #include <mach/gpio-exynos4.h>
22
23 #include <linux/delay.h>
24
25
26 //设备节点
27 #define DEVICE_NAME "jni"
28 //匹配项
29 #define DRIVER_NAME "jni"
30
31
32
33
34 MODULE_LICENSE("Dual BSD/GPL");
35 MODULE_AUTHOR("PNGCUI");
36
37
38 static int led_gpios[] = {
39 EXYNOS4212_GPJ0(1),EXYNOS4212_GPJ0(2),
40 };
41
42 #define GPIO_NUM ARRAY_SIZE(led_gpios)
43
44
45 static long jni_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
46 int ret;
47 printk("Hello JNI and cmd is %d,arg is %d\n",cmd,arg);
48
49 switch(cmd)
50 {
51 case 0:
52 case 1:
53 if (arg > 2) {
54 return -EINVAL;
55 }
56 gpio_set_value(led_gpios[arg], cmd);
57
58 break;
59
60 default:
61 return -EINVAL;
62 }
63
64 return 0;
65 }
66
67 static int jni_release(struct inode *inode, struct file *file){
68
69 printk("jni release\n");
70
71 return 0;
72 }
73
74
75 static int jni_open(struct inode *inode, struct file *file){
76
77 printk("jni open\n");
78
79
80 return nonseekable_open(inode,file);
81 }
82
83 static struct file_operations jni_ops = {
84 .owner = THIS_MODULE,
85 .open = jni_open,
86 .release = jni_release,
87 .unlocked_ioctl = jni_ioctl,
88 };
89
90 static struct miscdevice jni_dev = {
91 .minor = MISC_DYNAMIC_MINOR,
92 .name = DEVICE_NAME,
93 .fops = &jni_ops,
94 };
95
96 static int jni_probe(struct platform_device *pdv){
97 int ret,i;
98 printk("jni_probe start..\n");
99
100 for(i=0; i<GPIO_NUM; i++)
101 {
102 ret = gpio_request(led_gpios[i], "LED");
103 if (ret < 0) {
104 printk("%s: request GPIO %d for LED failed, ret = %d\n", DEVICE_NAME,i, ret);
105 }
106 else{
107 printk("%s: request GPIO %d for LED success, ret = %d\n", DEVICE_NAME,i, ret);
108 s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
109 gpio_set_value(led_gpios[i], 0);
110 //gpio_free(led_gpios[i]);
111 }
112 }
113
114 ret = misc_register(&jni_dev);
115 if(ret<0)
116 {
117 printk("jni:register device failed!\n");
118 goto exit;
119 }
120
121 return 0;
122
123 exit:
124 misc_deregister(&jni_dev);
125 return ret;
126 }
127
128 static int jni_remove(struct platform_device *pdv){
129 //int i;
130 printk("jni_remove...\n");
131
132 misc_deregister(&jni_dev);
133
134
135 return 0;
136 }
137
138 static void jni_shutdown(struct platform_device *pdv){
139
140 return ;
141 }
142
143 static int jni_suspend(struct platform_device *pdv,pm_message_t pmt){
144
145 return 0;
146 }
147
148 static int jni_resume(struct platform_device *pdv){
149
150 return 0;
151 }
152
153 struct platform_driver jni_driver = {
154 .probe = jni_probe,
155 .remove = jni_remove,
156 .shutdown = jni_shutdown,
157 .suspend = jni_suspend,
158 .resume = jni_resume,
159 .driver = {
160 .name = DRIVER_NAME,
161 .owner = THIS_MODULE,
162 }
163 };
164
165 static void jni_exit(void){
166
167 printk("jni_exit ...\n");
168
169 platform_driver_unregister(&jni_driver);
170
171 }
172
173 static int jni_init(void){
174
175 int err;
176
177 printk("jni_init start...\n");
178
179 err = platform_driver_register(&jni_driver);
180
181 printk("state is %d\n",err);
182
183 return 0;
184 }
185
186 module_init(jni_init);
187 module_exit(jni_exit);
View Code