• 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
  • 相关阅读:
    bootstrap 网格系统学习
    在asp.net web api中利用过滤器设置输出缓存
    解决在开发环境中访问json配置文件时报HTTP 错误 404.3
    Newtonsoft.Json序列化和反序列
    装饰者模式学习
    SQL server跨库查询
    python-安装xlrd xlwt 插件
    vim 实际行跟屏幕行移动命令
    vim-缓存区中打开另外一个文件的方法
    vim 计算器寄存器使用
  • 原文地址:https://www.cnblogs.com/pngcui/p/4766600.html
Copyright © 2020-2023  润新知