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

关键字: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两个端口

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

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

同样的,从init函数开始:

 1 static void jni_exit(void){
 2     
 3     printk("jni_exit ...
");
 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...
");
14     
15     err = platform_driver_register(&jni_driver);
16     
17     printk("state is %d
",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..
");
 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
", DEVICE_NAME,i, ret);
10             }
11         else{
12             printk("%s: request GPIO %d for LED success, ret = %d
", 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!
");
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...
");
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
",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
");
26     
27     return 0;
28 }
29 
30 
31 static int jni_open(struct inode *inode, struct file *file){
32     
33     printk("jni open
");
34     
35     
36     return nonseekable_open(inode,file);
37 }

最后附上完整的驱动代码

  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
",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
");
 70     
 71     return 0;
 72 }
 73 
 74 
 75 static int jni_open(struct inode *inode, struct file *file){
 76     
 77     printk("jni open
");
 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..
");
 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
", DEVICE_NAME,i, ret);
105             }
106         else{
107             printk("%s: request GPIO %d for LED success, ret = %d
", 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!
");
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...
");
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 ...
");
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...
");
178     
179     err = platform_driver_register(&jni_driver);
180     
181     printk("state is %d
",err);
182     
183     return 0;
184 }
185 
186 module_init(jni_init);
187 module_exit(jni_exit);
View Code
原文地址:https://www.cnblogs.com/pngcui/p/4766600.html